2013-06-05 32 views
4

問題:Linq.Expression VB中的GetValue?

我有這個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_$VB$Local_mytable.tablename

現在我想知道我必須要改變這個工作中VB.NET。
任何人都知道/有線索?

編輯:
嗯,這個問題似乎是由「選項推斷關」在項目範圍內的設置引起的。
所以這個問題變成了:如何通過「Option Infer Off」做到這一點?

+2

你VB代碼工作正常,我。 – svick

+0

對我來說也都很好(VS 2008,x64) – Pondidum

+0

@svick:啊,非常有趣。這留下了一個可能的原因。經過測試的假設和發現的權利 - >該問題是由項目範圍設置中的「Option Infer Off」造成的。現在新的問題是我需要做些什麼才能使它與infer = off一起工作。 –

回答

2

你的問題與表達式樹無關(如果你打擾包括你得到的錯誤會更容易發現)。

你有Option Infer OffOption Strict Off和下面的代碼:

Dim getter = getterLambda.Compile() 

Return getter() 

會拋出MissingMemberException

沒有默認成員發現型 'Func鍵(對象)'。

的問題是,()在這裏解釋爲調用默認成員,而不是調用一個委託,因爲getter的類型爲Object。要解決這一點,你可以指定變量的類型:

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

Return getter() 

,或者您可以使用更詳細的語法來調用一個委託:

Dim getter = getterLambda.Compile() 

Return getter.Invoke() 
+0

噢,廢話,這只是演示瞭如何使用「Option Strict Off」(和「Option Infer On」與var在C#中)是多麼錯誤。謝謝 ! –