问题
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" ?
回答1:
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()
来源:https://stackoverflow.com/questions/16939535/linq-expression-getvalue-in-vb