我正在尝试创建一个方法,该方法返回给定类型的委托,其中主体运行函数中指定的某些代码。IE
public Delegate GenerateDelegate(Type delegateType)
{
// create a delegate of type 'Type'
// specify the code of this delegate
// return the delegate object
}
Run Code Online (Sandbox Code Playgroud)
如果我事先知道类型,或者至少是参数和返回类型,我显然可以只返回该类型的委托,匿名委托,以及我想要的任何代码。但是,问题是我希望它适用于几乎任何类型的非通用委托,并且我希望能够利用委托类型具有的参数,并返回正确的类型。
我查看了使用ILGenerator.Emit()或CodeDOM来实现此目的的不同选项。但是,我可能想在返回的委托中做一些非常复杂的事情,并且希望能够直接在 C# 中进行编码,因为我不确定我是否可以使用 IL 或CodeDOM实现这一点。作为伪解决方案,与Delegate.DynamicInvoke(params object[])可以采用匿名参数一样,我想我希望能够做这样的事情。
public Delegate GenerateDelegate(Type delegateType)
{
return Delegate.CreateDelegate(delegateType, GetType().GetMethod("RunEvent"));
}
public static object RunEvent(params object[] parameters)
{
// some specified code, depending on contents of parameters
return null;
}
Run Code Online (Sandbox Code Playgroud)
所述RunEvent()可以采取任何数量的参数作为对象阵列,并且返回对象。可悲的是,这不起作用并引发以下异常:
无法绑定到目标方法,因为其签名或安全透明度与委托类型的签名或安全透明度不兼容。
不知何故,我认为对象数组参数应该与委托可能具有的任何参数组合兼容,但返回类型是一个对象,可能会返回一些与给定的delegateType不兼容的对象,或者如果delegateType返回 void。这可能会导致一些问题。
对于我自己的用法,我知道运行时的所有参数和返回类型,并且可以检查这一点以确保一切都是安全的。有什么办法可以让我这样工作吗?
我找到了解决我的问题的方法,但它确实需要我使用泛型。在某种程度上,它是一个更安全的解决方案,因为我需要向生成器提供所请求的委托及其类型。
虽然该解决方案并不完全是我所希望的,但它确实解决了我目前的问题并回答了我原来的问题。然而,我将来可能不得不转向更复杂的解决方案。
如果有人能看到进一步的简化,请告诉我。
(我发现这一点要归功于 Anis 关于探索表达式树的建议,因为它采用了类似的方法。)
public class DelegateGenerator<TDelegate, TReturn>
: GenBase<TDelegate, TReturn> where TDelegate : class
{
public TReturn RunEvent() => runEvent();
}
public class DelegateGenerator<TDelegate, TReturn, T>
: GenBase<TDelegate, TReturn> where TDelegate : class
{
public TReturn RunEvent(T a) => runEvent(a);
}
public class DelegateGenerator<TDelegate, TReturn, T1, T2>
: GenBase<TDelegate, TReturn> where TDelegate : class
{
public TReturn RunEvent(T1 a, T2 b) => runEvent(a, b);
}
// etc
public abstract class GenBase<TDelegate, TReturn> where TDelegate : class
{
public TDelegate GenerateDelegate()
{
var method = GetType().GetMethod("RunEvent");
return Delegate.CreateDelegate(typeof(TDelegate), this, method) as TDelegate;
}
protected TReturn runEvent(params object[] objs)
{
// some code
return (TReturn)result;
}
}
Run Code Online (Sandbox Code Playgroud)
及用法:
public delegate bool myDelegate(int a, bool b);
var gen = new DelegateGenerator<myDelegate, bool, int, bool>();
var del = gen.GenerateDelegate();
var result = del(5, true);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2511 次 |
| 最近记录: |