使用anonymous methods,您可以创建自C#2.0以来的空委托。
public event EventHandler SomeEvent = delegate {};
public event Action OtherEvent = delegate {};
这是例如useful to prevent having to do the null check when invoking events
如何使用Expression Trees创建相同的行为?
我现在看到的唯一可能的选择是使用Expression.Lambda()
,但据我所知,这将需要大量的额外工作。
答案 0 :(得分:5)
表达式树,就其目的而言,总是有一个表达式而不是原始设计中的语句。
在C#3中,根本没有办法表达一个表达式树,它的主体是一个空语句块。最近,表达式树库已经扩展到允许语句,但C#语义分析规则没有更新以利用它;你仍然无法将语句lambda转换为表达式树。
答案 1 :(得分:2)
事实证明 使用Expression.Lambda()
。但是,我仍然对其他可能的答案感兴趣。
我确实需要一个我之前写过的辅助方法:
/// <summary>
/// The name of the Invoke method of a Delegate.
/// </summary>
const string InvokeMethod = "Invoke";
/// <summary>
/// Get method info for a specified delegate type.
/// </summary>
/// <param name = "delegateType">The delegate type to get info for.</param>
/// <returns>The method info for the given delegate type.</returns>
public static MethodInfo MethodInfoFromDelegateType( Type delegateType )
{
Contract.Requires(
delegateType.IsSubclassOf( typeof( MulticastDelegate ) ),
"Given type should be a delegate." );
return delegateType.GetMethod( InvokeMethod );
}
当你有EventInfo
时,你可以为它创建一个空的lambda,如下所示:
EventInfo _event;
...
MethodInfo delegateInfo
= DelegateHelper.MethodInfoFromDelegateType( _event.EventHandlerType );
ParameterExpression[] parameters = delegateInfo
.GetParameters()
.Select( p => Expression.Parameter( p.ParameterType ) )
.ToArray();
Delegate emptyDelegate = Expression.Lambda(
_event.EventHandlerType,
Expression.Empty(), "EmptyDelegate", true, parameters ).Compile();
答案 2 :(得分:1)
扩展Steven的答案 - 我需要类似的功能来为两者创建一个空委托 - Action和Func类型 - 以下是我为该任务创建的帮助程序:
static class MethodInfoHelper<T>
{
static MethodInfoHelper()
{
VerifyTypeIsDelegate();
}
public static void VerifyTypeIsDelegate()
{
//Lets make sure this is only ever used in code for Func<> types
if (!typeof(T).IsSubclassOf(typeof(Delegate)))
{
throw new InvalidOperationException(typeof(T).Name + " is not a delegate type");
}
if (!typeof(T).Name.StartsWith("Func") && !typeof(T).Name.StartsWith("Action"))
{
throw new InvalidOperationException(typeof(T).Name + " is not a Func nor an Action");
}
}
private static bool HasReturnType
{
get { return typeof(T).Name.StartsWith("Func"); }
}
/// <summary>
/// Creates an empty delegate of given type
/// </summary>
/// <typeparam name="T">Func or Action type to be created</typeparam>
/// <returns>A delegate to expression doing nothing</returns>
public static T CreateEmptyDelegate()
{
Type funcType = typeof(T);
Type[] genericArgs = funcType.GenericTypeArguments;
List<ParameterExpression> paramsExpressions = new List<ParameterExpression>();
for (int paramIdx = 0; paramIdx < (HasReturnType ? genericArgs.Length - 1 : genericArgs.Length); paramIdx++)
{
Type argType = genericArgs[paramIdx];
ParameterExpression argExpression = Expression.Parameter(argType, "arg" + paramIdx);
paramsExpressions.Add(argExpression);
}
Type returnType = HasReturnType ? genericArgs.Last() : typeof(void);
DefaultExpression emptyExpression = (DefaultExpression)typeof(DefaultExpression).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null,
new Type[] { typeof(Type) }, null).Invoke(new[] { returnType });
Expression<T> resultingExpression = Expression.Lambda<T>(
emptyExpression, "EmptyDelegate", true, paramsExpressions);
return resultingExpression.Compile();
}
}