Question

Question:

I have this C# program, that gets the value of field tablename of mytable.
And it works fine.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;


namespace AttachObjectsCS
{


    static class Program
    {


        public class cmytable
        {
            public string tablename = "test";
        }


        // http://stackoverflow.com/questions/2616638/access-the-value-of-a-member-expression
        private static object GetValue(System.Linq.Expressions.MemberExpression member)
        {
            System.Linq.Expressions.Expression objectMember = System.Linq.Expressions.Expression.Convert(member, typeof(object));
            System.Linq.Expressions.Expression<Func<object>> getterLambda = System.Linq.Expressions.Expression.Lambda<Func<object>>(objectMember);

            var getter = getterLambda.Compile();

            return getter();
        }


        public static void AddField<T>(System.Linq.Expressions.Expression<Func<T>> expr, string alias)
        {
            var body = ((System.Linq.Expressions.MemberExpression)expr.Body);
            Console.WriteLine("Name is: {0}", body.Member.Name);


            object obj = GetValue(body);


            Console.WriteLine("Value is: {0}", obj);
        }



        /// <summary>
        /// Der Haupteinstiegspunkt für die Anwendung.
        /// </summary>
        [STAThread]
        static void Main()
        {

            if (false)
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());
            }


            cmytable mytable = new cmytable();

            AddField(() => mytable.tablename, "te");


            Console.WriteLine(Environment.NewLine);
            Console.WriteLine(" --- Press any key to continue --- ");
            Console.ReadKey();
        } // End Sub Main 


    } // End Class Program


} // End Namespace AttachObjectsCS

Now I need the same functionality in VB.NET, but it fails.
Now since I'm aware that VB.NET and C# don't always use the same linq expression, I'm not surprised that I run into a problem here.

Module Program




    Public Class cmytable
        Public tablename As String = "test"
    End Class


    Public Sub AddField(Of T)(expr As System.Linq.Expressions.Expression(Of Func(Of T)))
        Dim body = DirectCast(expr.Body, System.Linq.Expressions.MemberExpression)
        Dim strName As String = body.Member.Name
        Console.WriteLine("Name is: {0}", strName)


        Dim obj As Object = GetValue(body)


        Console.WriteLine("Value is: {0}", obj)
    End Sub


    ' http://stackoverflow.com/questions/2616638/access-the-value-of-a-member-expression '
    Private Function GetValue(member As System.Linq.Expressions.MemberExpression) As Object
        Dim objectMember As System.Linq.Expressions.Expression = System.Linq.Expressions.Expression.Convert(member, GetType(Object))
        Dim getterLambda As System.Linq.Expressions.Expression(Of Func(Of Object)) = System.Linq.Expressions.Expression.Lambda(Of Func(Of Object))(objectMember)


        Dim getter = getterLambda.Compile()

        Return getter()
    End Function



    Public Sub Main()

        Dim mytable As New cmytable

        AddField(Function() mytable.tablename)
    End Sub


End Module ' Program

The problem is in GetValue, and the problem is that I don't seem to have the proper objectMember.

Here the debug output for the expressions:

CS objectMember = {Convert(value(AttachObjectsCS.Program+<>c__DisplayClass0).mytable.tablename)}
VB objectMember = {Convert(value(AttachObjects.Program+_Closure$__1).$VB$Local_mytable.tablename)}

CS getterLambda = {() => Convert(value(AttachObjectsCS.Program+<>c__DisplayClass0).mytable.tablename)}
VB getterLambda = {() => Convert(value(AttachObjects.Program+_Closure$__1).$VB$Local_mytable.tablename)}

My guess would be that the problem is the $VB$Local_ in $VB$Local_mytable.tablename

Now I'm wondering what I have to change for this to work in VB.NET.
Anybody knows / has a clue ?

Edit:
Ah, the problem seems to be caused by "Option Infer Off" in the project wide settings.
So the the question alters and becomes: How to do this with "Option Infer Off" ?

Était-ce utile?

La solution

Your problem has nothing to do with expression trees (which would be easier to spot if you bothered to include the error you're getting).

You have Option Infer Off and Option Strict Off and the following code:

Dim getter = getterLambda.Compile()

Return getter()

which throws MissingMemberException:

No default member found for type 'Func(Of Object)'.

The problem is that () is here interpreted as invoking the default member and not invoking a delegate, because getter is typed as Object. To work around that, you can specify the type of the variable:

Dim getter As Func(Of Object) = getterLambda.Compile()

Return getter()

or you can use more verbose syntax for invoking a delegate:

Dim getter = getterLambda.Compile()

Return getter.Invoke()
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top