2011-06-22 8 views
0

EDIT例外が

を私は例外私はLINQの式を作成しようとする任意の時間を取得していますクラスまたはモジュール内のローカルに定義されたデリゲート(またはラムダ)または関数への呼び出しを含むメソッドからの呼び出し。

私は2つのパラメータ(デリゲートと整数)を取り、それは結果を取得するために使用するLINQ MethodCallExpressionを作成する関数持っている:私はエラーなしでこのコードを実行することができます

Public Delegate Function CompareTwoIntegerFunction(ByVal i1 As Integer, ByVal i2 As Integer) As Boolean 
Public Function Test(ByVal pFunc As CompareTwoIntegerFunction, ByVal i1 As Integer, ByVal i2 As Integer) As Boolean 
    Dim lParamExpression As ParameterExpression = Expression.Parameter(GetType(Integer), "i") 
    Dim lConstExpr As ConstantExpression = Expression.Constant(i1, GetType(Integer)) 
    Dim lMatcher As CompareTwoIntegerFunction = pFunc 

    ' *** This line throws the exception (line 17) 
    Dim lMatcherExpr As MethodCallExpression = Expression.Call(lMatcher.Method, lParamExpression, lConstExpr) 

    ' Now use the expression and get the result 
    Dim lFunc As Func(Of Integer, Boolean) = (Expression.Lambda(Of Func(Of Integer, Boolean))(lMatcherExpr, lParamExpression)).Compile 

    Return lFunc(i2) 
End Function 

をこのテストでは:

Dim lMatchedPass1 As Boolean = Test(Function(a, b) a = b, 10, 10) 

私も空想取得し、このような何か行うことができます。

Dim lMatchedPass2 As Boolean = Test(Function(a, b) (Function(c As Integer) c + 1)(a) = b, 10, 9) 

Dim ChildFunc As Func(Of Integer, Integer) = Function(s As Integer) s + 1 
    Dim MatchedFail1 As Boolean = Test(Function(a, b) (ChildFunc(a)) = b, 10, 9) 

例外メッセージ:

Exception: [2011 Jun 23 (Thu) 10:25:29 AM] [ System.Core ] 
Value cannot be null. 
Parameter name: instance 
    at System.Linq.Expressions.Expression.ValidateCallArgs(Expression instance, MethodInfo method, ReadOnlyCollection`1& arguments) 
    at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, IEnumerable`1 arguments) 
    at System.Linq.Expressions.Expression.Call(MethodInfo method, Expression[] arguments) 
    at DataManager`1.Test(CompareTwoIntegerFunction pFunc, Int32 i1, Int32 i2) in DataManager.vb:line 17 
    at DataManager`1..ctor() in DataManager.vb:line 27 
Called from: Void ValidateCallArgs(System.Linq.Expressions.Expression, System.Reflection.MethodInfo, System.Collections.ObjectModel.ReadOnlyCollection`1[System.Linq.Expressions.Expression] ByRef) 

私はMatchTest2は大丈夫ですが、MatchFail1が問題である理由を理解したい、私はこのような何かをしようとすると210

はしかし、その後、私は例外を取得します。

注1:上記の例では定数とパラメータを使用していますが、2つの定数または2つのパラメータで同じ結果が得られます。私は、名前付き代理人型を無名関数定義に置き換えることによって例外を得ることもできます。

注2:

Dim lMatcherExpr As MethodCallExpression = Expression.Call(Nothing, pFunc.Method, lParamExpression, lConstExpr) 

注3: 私がいることを見つけた 私はこのように、Expression.CallラインにインスタンスパラメータとしてNothingを追加し、成功せず、試してみました上記のコードで私の "子関数"をモジュールに移動したり、クラス内の "共有"関数にすることで問題を "修正"できます。これは子関数をパラメータとして渡すことができるため、非常に現実的な解決策ではありませんが、自明ではありません。言い換えれば

、私の目標は、このような何かを行うことです。

Public Function RunTestWithChildFunction(ByVal a As Integer, ByVal b As Integer, ByVal ChildFunc As Func(Of Integer, Integer, Boolean)) As Boolean 
    Return Test(Function(x, y) ChildFunc(x, y), a, b) 
End Function 
Public Function EqualityCheck(ByVal a As Integer, ByVal b As Integer) As Boolean 
    Return a = b 
End Function 
Public Sub DoTest 
    Dim lMatchedFail2 As Boolean = RunTestWithChildFunction(10, 10, AddressOf EqualityCheck) 
End 

アドレスは(私が手RunCheckWithChildFunctionByValを渡されるため、このコードではEqualityCheckに「共有」を追加しても問題が解決しません私がそれを渡そうとするとコンパイル失敗ByRef)。

答えて

0

中間クラスを導入することで問題を回避できるようです。クラスインスタンスは、 "内側の"ラムダ関数へのアドレスを保持します。これに代えので

、:

Dim lMatchedPass2 As Boolean = Test(Function(a As Integer, b As Integer) (Function(c As Integer) c + 1)(a) = (b + 1), 10, 10) 

    Dim ChildFunc As Func(Of Integer, Integer) = Function(s As Integer) s + 1 
    Dim MatchedFail1 As Boolean = Test(Function(a, b) (ChildFunc(a)) = b, 10, 9) 

私はこのような呼び出し必要があります:

Public Function TestClass(Of T)(ByVal pComparator As IDoCompare(Of T), ByVal pValue As T) As Boolean 
    Dim lParamExpression As ParameterExpression = Expression.Parameter(GetType(T), "t") 
    Dim lCompareFunc As IDoCompare(Of T).Compare = AddressOf pComparator.DoCompare 
    Dim lInstance As ConstantExpression = Expression.Constant(pComparator) 
    Dim lMatcherExpr As MethodCallExpression = Expression.Call(lInstance, lCompareFunc.Method, lParamExpression) 

    Dim lFunc As Func(Of T, Boolean) = (Expression.Lambda(Of Func(Of T, Boolean))(lMatcherExpr, lParamExpression)).Compile 
    Return lFunc(pValue) 
End Function 

Interface IDoCompare(Of T) 
    Delegate Function Compare(ByVal pParam As T) As Boolean 
    Function DoCompare(ByVal pParam As T) As Boolean 
End Interface 

Class DoCompare(Of T) : Implements IDoCompare(Of T) 
    Protected mClue As T 
    Sub New(ByVal pClue As T) 
     mClue = pClue 
    End Sub 
    Public Comparator As Func(Of T, T, Boolean) = Function(a As T, B As T) a.ToString = B.ToString 
    Public Function DoCompare(ByVal pParam As T) As Boolean Implements IDoCompare(Of T).DoCompare 
     Return Comparator(mClue, pParam) 
    End Function 
End Class 
:新しいクラスは次のようになり

Dim lDoCompare As New DoCompare(Of Integer)(10) 
    lDoCompare.Comparator = Function(a As Integer, b As Integer) (Function(c As Integer) c + 1)(a) = (b + 1) 
    Dim lMatchClassPass1 as Boolean = TestClass(lDoCompare, 10) 

    Dim ChildFunc As Func(Of Integer, Integer) = Function(c As Integer) c + 1 
    lDoCompare.Comparator = Function(a As Integer, b As Integer) ChildFunc(a) = (b + 1) 
    Dim lMatchClassPass2 as Boolean = TestClass(lDoCompare, 10)