Ste*_*ris 13 c# lambda expression-trees
当我使用Expression.Lambda( ... ).Compile()从表达式树创建委托时,结果是第一个参数的委托Closure.
public static Func<T, T, T> CreateTest<T>()
{
ParameterExpression a = Expression.Parameter( typeof( T ) );
ParameterExpression b = Expression.Parameter( typeof( T ) );
Expression addition = Expression.Add( a, b );
return (Func<T, T, T>)Expression.Lambda( addition, a, b ).Compile();
}
...
// 'addition' equals
// Int32 lambda_method(
// System.Runtime.CompilerServices.Closure,
// Int32,
// Int32 )
Func<int, int, int> addition = DelegateHelper.CreateTest<int>();
int result = addition( 5, 5 );
Run Code Online (Sandbox Code Playgroud)
我可以轻松地通过普通代码调用委托而不传递Closure对象,但这是Closure从哪里来的?
如何动态调用此委托?
// The following does not work.
// Exception: MethodInfo must be a runtime MethodInfo object.
MethodInfo additionMethod = addition.Method;
int result = (int)additionMethod.Invoke( null, new object[] { 5, 5 } );
Run Code Online (Sandbox Code Playgroud)
使用表达式树看起来我必须传递Closure对象.
PropertyInfo methodProperty
= typeof( Delegate ).GetProperty( "Method", typeof( MethodInfo ) );
MemberExpression getDelegateMethod
= Expression.Property( Expression.Constant( addition ), methodProperty );
Func<MethodInfo> getMethodInfo
= (Func<MethodInfo>)Expression.Lambda( getDelegateMethod ).Compile();
// Incorrect number of arguments supplied for call to method
// 'Int32 lambda_method(System.Runtime.CompilerServices.Closure, Int32, Int32)'
Expression call
= Expression.Call(
getMethodInfo(),
Expression.Constant( 5 ), Expression.Constant( 5 ) );
Run Code Online (Sandbox Code Playgroud)
这是一个简单的例子,它本身没有意义.什么,我其实是想实现的是要能包住如Func<Action<SomeObject>>用Func<Action<object>>.我已经可以为非嵌套委托执行此操作.这在反射期间很有用,如此处所讨论的.
我该如何正确初始化此Closure对象,或者如何防止它出现?
Jb *_*ain 13
Closure您看到的类型是实现细节.在MSDN是相当明确一下:
此API支持.NET Framework基础结构,不能直接在您的代码中使用.表示动态生成的方法的运行时状态.
表达式树可以具有状态.
Closure实例将包含lambda表达式关闭的所有非文字常量.它还可以包含表达式树中嵌套lambda的委托链.
为实现这一点,表达式树编译器使用了一个可爱的小技巧.它使用a生成内存代码DynamicMethod,根据定义静态.然而,他们正在创建一个"关闭其第一个论点"的代表.这意味着CLR将传递委托的目标字段作为静态方法的第一个参数,因此您不必这样做.有效地隐藏了你的Closure参数.
解决问题的方法很简单,不要尝试调用方法,调用委托,或者在使用反射时使用Delegate.DynamicInvoke,或者在表达式树的上下文中使用Expression.Invoke.
| 归档时间: |
|
| 查看次数: |
4287 次 |
| 最近记录: |