Search code examples
vb.netlinqlinq-expressions

Determine Object from Object.Property (used in persisting settings)


I have made a simple Class to save user settings. All is working well but I'd like to simplify/generalize a little more, but I am having trouble getting the Object (TestSavedSettings) from it's Property (FormLocation). As seen in the code below I am able to get the Form1 object from it's Location Property... but I can't get it to work the same for the TestSavedSettings.FormLocation.

The code below is complete and can be cut pasted into a new VB Windows Forms Application and run, it will persist the forms location for each start up.

Bottom line: How can I get the Object that is for the TestSettings.AddBinding 'sn' argument? (just as I am doing successfully for the 'pn' argument?


Imports System.Linq.Expressions Imports System.Configuration Imports System.Reflection Public Class Form1 Private TestSavedSettings As New TestSettings_TestForm Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load TestSavedSettings.AddBinding(Function() Me.Location, Function() TestSavedSettings.FormLocation) 'Below is what I would like to use instead of the version in the line above ' TestSettings.AddBinding(Function() Me.Location, Function() TestSavedSettings.FormLocation) End Sub Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing TestSavedSettings.Save() End Sub End Class Public Class TestSettings_TestForm : Inherits ApplicationSettingsBase <UserScopedSettingAttribute()> Public Property FormLocation() As Point Get Return CType(Me(MethodBase.GetCurrentMethod().Name.Remove(0, 4)), Point) End Get Set(ByVal value As Point) Me(MethodBase.GetCurrentMethod().Name.Remove(0, 4)) = value End Set End Property '--This alternative method works, but I'd like to just have one shared version of this in a seperate Class as shown at end Public Sub AddBinding(Of T, T2)(ByVal pn As Expression(Of Func(Of T)), ByVal sn As Expression(Of Func(Of T2))) Dim FrmPropertyName As String = DirectCast(pn.Body, MemberExpression).Member.Name Dim Frm As Form = DirectCast(DirectCast(DirectCast(pn.Body, MemberExpression).Expression, ConstantExpression).Value, Form) Dim SettingName As String = DirectCast(sn.Body, MemberExpression).Member.Name Frm.DataBindings.Add(New Binding(FrmPropertyName, Me, SettingName, True, DataSourceUpdateMode.OnPropertyChanged)) End Sub End Class Public Class TestSettings Public Shared Sub AddBinding(Of T, T2)(ByVal pn As Expression(Of Func(Of T)), ByVal sn As Expression(Of Func(Of T2))) Dim FrmPropertyName As String = DirectCast(pn.Body, MemberExpression).Member.Name Dim Frm As Form = DirectCast(DirectCast(DirectCast(pn.Body, MemberExpression).Expression, ConstantExpression).Value, Form) Dim SettingName As String = DirectCast(sn.Body, MemberExpression).Member.Name '>>>>>Problem is with line below, causes exception, .Expression is actrually returning a FieldExpression not a ConstantExpression, 'but can't cast to that.... Dim Setting As Object = DirectCast(DirectCast(sn.Body, MemberExpression).Expression, ConstantExpression).Value Frm.DataBindings.Add(New Binding(FrmPropertyName, Setting, SettingName, True, DataSourceUpdateMode.OnPropertyChanged)) End Sub :End Class


Solution

  • One way to do what you want would be to to compile and execute the sub-expression that contains the value that you need, instead of trying to process it manually:

    Dim settingExpression = DirectCast(sn.Body, MemberExpression).Expression
    Dim setting = Expression.Lambda(Of Func(Of Object))(settingExpression).Compile().Invoke()