我有一个给定委托(delegate)的方法 Type
参数(不是通用的),它返回一个 Delegate
它创建的实现签名的。它在内部使用表达式树创建动态方法。委托(delegate)类型必须是这种形式 Func<SomeParam,IamDerivedObject>
, 一个函数,其中 IamDerivedObject 是 IamDerivedObject 的继承者。该方法使用类型信息来确定要实例化的对象,因此简单地使用接口(interface)进行创建将是灾难性的。调用是从返回 IamDerivedObject
的静态方法完成的.
在 .NET 4 代码中,我可以这样做::
var myDelegate = MakeMethod(typeArgument) as Func<SomeParam,IamDerivedObject>
在 .Net 3.5 中这不起作用。而且我不得不知道调用调用方法的类型,或者使用另一个表达式生成的委托(delegate)来调用它并缓存该委托(delegate)。这意味着更多的运行时生成代码。 不幸的是,我暂时不能使用 .NET 4 代码,因为程序集必须是 .NET 3.5 代码,因为它依赖于在 4.0 中不起作用的第三方 dll。
最佳答案
我想出了一个方法,但它基本上需要一些反射魔法才能弄清楚。
/// <summary>
/// Converts the delegate to <see cref="TDelegate"/>, provided the types are compatible. Can use
/// variance of delegate typing in .NET 4 for a speedy conversion. Otherwise, uses Delegate.CreateDelegate
/// to create a new delegate with the appropriate signature.
/// </summary>
/// <typeparam name="TDelegate">The target delegate type.</typeparam>
/// <param name="delegate">The @delegate.</param>
/// <returns></returns>
public static TDelegate ConvertDelegate<TDelegate>(Delegate @delegate) where TDelegate : class
{
ArgumentValidator.AssertIsNotNull(() => @delegate);
var targetType = typeof(TDelegate);
ArgumentValidator.AssertIsDelegateType(() => targetType);
var currentType = @delegate.GetType();
if (targetType.IsAssignableFrom(currentType))
{
return @delegate as TDelegate; // let's skip as much of this as we can.
}
var currentMethod = currentType.GetMethod("Invoke");
var targetMethod = targetType.GetMethod("Invoke");
if (!AreDelegateInvokeMethodsCompatible(currentMethod, targetMethod, true))
{
throw new ArgumentException(string.Format("{0} is incompatible with {1}.", currentType, targetType), ExpressionHelper.GetMemberName(() => @delegate));
}
var invocationList = @delegate.GetInvocationList();
return DelegateHelper.Combine(@delegate.GetInvocationList()
.Select(d => IsMethodRunTimeGenerated(d.Method) ?
GetDynamicMethodFromMethodInfo(d.Method).CreateDelegate<TDelegate>(d.Target) :
DelegateHelper.CreateDelegate<TDelegate>(d.Target, d.Method)).ToArray());
}
#region Private Static Variables
private static Type s_RTDynamicMethodType = Type.GetType("System.Reflection.Emit.DynamicMethod+RTDynamicMethod",false,true);
private static Func<MethodInfo, DynamicMethod> s_GetDynamicMethodDelegate = CreateGetDynamicMethodDelegate();
#endregion Private Static Variables
private static Func<MethodInfo, DynamicMethod> CreateGetDynamicMethodDelegate()
{
var param = Expression.Parameter(
typeof(MethodInfo),
typeof(MethodInfo).Name
);
var expression = Expression.Lambda<Func<MethodInfo, DynamicMethod>>(
Expression.Field(
Expression.Convert(
param,
s_RTDynamicMethodType
),
s_RTDynamicMethodType.GetField("m_owner", BindingFlags.NonPublic | BindingFlags.Instance)
),
param
);
return expression.Compile();
}
我不会放弃我的 delegatehelper 类,除非其他人真的需要它。但关键是这是可能的,而且实际上非常快。转换通常小于 1 毫秒,不如接近瞬时的方法组转换快,但你知道那是什么。
关于c# - 在 .NET 3.5 委托(delegate)中模拟差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3920684/