【问题标题】:Linq.Expression GetValue in VB?VB中的Linq.Expression GetValue?
【发布时间】:2013-06-05 12:07:00
【问题描述】:

问题:

我有这个 C# 程序,它获取 mytable 的字段 tablename 的值。
而且效果很好。

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

现在我需要 VB.NET 中的相同功能,但它失败了。
现在,因为我知道 VB.NET 和 C# 并不总是使用相同的 linq 表达式,所以我在这里遇到问题并不感到惊讶。

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

问题出在GetValue,问题是我似乎没有合适的objectMember。

这里是表达式的调试输出:

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)}

我的猜测是问题出在$VB$Local_mytable.tablename 中的$VB$Local_

现在我想知道我必须改变什么才能在 VB.NET 中工作。
有人知道/有线索吗?

编辑:
啊,问题似乎是由项目范围设置中的“选项推断关闭”引起的。
所以问题变成了:如何使用“Option Infer Off”来做到这一点?

【问题讨论】:

  • 你的 VB 代码对我来说很好。
  • 对我来说两者都运行良好(VS 2008,x64)
  • @svick:啊,很有趣。这留下了一个可能的原因。测试假设并发现正确-> 问题是由项目范围设置中的“选项推断关闭”引起的。现在的新问题是我需要做些什么才能让它与 infer = off 一起工作。
  • 保留选项推断?让编译器为您完成工作真是太好了:)
  • @Pondidum:不,因为在运行时而不是编译时遇到一些其他错误并不是很好。已经很糟糕了,我必须禁用选项严格,因为我(必须)使用 oledb-com-objects(这需要后期绑定——>这反过来又需要选项严格关闭)。

标签: c# vb.net linq lambda linq-expressions


【解决方案1】:

您的问题与表达式树无关(如果您费心将遇到的错误包含在内,则更容易发现)。

您有Option Infer OffOption Strict Off 以及以下代码:

Dim getter = getterLambda.Compile()

Return getter()

抛出MissingMemberException:

找不到类型“Func(Of Object)”的默认成员。

问题在于() 在这里被解释为调用默认成员而不是调用委托,因为getter 被键入为Object。要解决这个问题,您可以指定变量的类型:

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

Return getter()

或者您可以使用更详细的语法来调用委托:

Dim getter = getterLambda.Compile()

Return getter.Invoke()

【讨论】:

  • 哦,废话,这只是演示了在 C# 中使用“Option Strict Off”(以及“Option Infer On”和 var)是多么错误。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-11
  • 1970-01-01
  • 2020-08-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多