Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/rust/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 创建具有未知参数和返回类型的委托_C#_Delegates - Fatal编程技术网

C# 创建具有未知参数和返回类型的委托

C# 创建具有未知参数和返回类型的委托,c#,delegates,C#,Delegates,我正在尝试创建一个方法,该方法返回给定类型的委托,主体运行函数中指定的特定代码。i、 e public Delegate GenerateDelegate(Type delegateType) { // create a delegate of type 'Type' // specify the code of this delegate // return the delegate object } 如果我事先知道类型

我正在尝试创建一个方法,该方法返回给定类型的委托,主体运行函数中指定的特定代码。i、 e

    public Delegate GenerateDelegate(Type delegateType)
    {
        // create a delegate of type 'Type'
        // specify the code of this delegate
        // return the delegate object
    }
如果我事先知道类型,或者至少知道参数&返回类型,那么我显然可以返回该类型的委托,一个匿名委托,以及我想要的任何代码。但是,问题是,我希望它适用于几乎任何类型的非泛型委托,并且我希望能够使用委托类型具有的参数,并返回正确的类型

我已经研究了使用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;
    }
RunEvent()可以将任意数量的参数作为对象数组,并返回对象。遗憾的是,这不起作用,并引发以下异常:

无法绑定到目标方法,因为其签名或安全透明性与委托类型的签名或安全透明性不兼容

不知何故,我认为对象数组参数应该与委托可能具有的任何参数组合兼容,但返回类型为对象,可能返回与给定的delegateType不兼容的对象,或者如果delegateType返回void。这可能会导致一些问题


对于我自己的使用,我知道运行时的所有参数和返回类型,并且可以检查以确保一切都是安全的。有什么方法可以让这样的东西工作吗?

是的,你可以沿着“原始”IL生成路线。但是如果使用方法的主体将允许使用它,请考虑使用。

下面是一个简单的示例,它只返回返回类型的默认值,而忽略所有参数(这只是一个玩具示例;实际实现需要复杂得多——例如处理
out
params):

用法:

Type[] parameterTypes = { typeof(string), typeof(double) };
var returnType = typeof(int);   

var del = CreateDelegate(parameterTypes, returnType);

//Output: System.Func`3[System.String,System.Double,System.Int32]
del.GetType().Dump();

//Output: 0
del.DynamicInvoke("abc", 5D).Dump();

我为我的问题找到了一个解决方案,但它确实需要我使用泛型。在某种程度上,这是一个更安全的解决方案,因为我需要向生成器提供请求的委托及其类型

虽然这个解决方案并不是我所希望的,但它确实为我解决了目前的问题,并回答了我最初的问题。不过,我将来可能不得不转向更复杂的解决方案

如果有人能看到进一步的简化,请让我知道

(我发现这一点要感谢Anis关于探索表达式树的建议,因为它采用了类似的方法。)

公共类委托生成器
:GenBase其中TDelegate:class
{
public TReturn RunEvent()=>RunEvent();
}
公共类委托生成器
:GenBase其中TDelegate:class
{
公共TReturn运行事件(TA)=>运行事件(a);
}
公共类委托生成器
:GenBase其中TDelegate:class
{
公共TReturn运行事件(T1 a,T2 b)=>运行事件(a,b);
}
//等
公共抽象类GenBase,其中TDelegate:class
{
公共TDelegate GenerateDelegate()
{
var method=GetType().GetMethod(“RunEvent”);
返回Delegate.CreateDelegate(typeof(TDelegate),this,method)作为TDelegate;
}
受保护的TReturn runEvent(参数对象[]objs)
{
//一些代码
返回(TReturn)结果;
}
}
使用方法:

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);
公共委托bool myDelegate(inta,bool b);
var gen=新的DelegateGenerator();
var del=gen.GenerateDelegate();
var结果=del(5,真);

“对象数组参数应与代理可能具有的任何参数组合兼容”–实际上并非如此。它们与
ref
/
out
参数不匹配,它们与值类型参数不匹配(通常调用此类方法时未应用隐式装箱)。完全不知道你们将要调用的方法似乎是一种非常错误的方法。你们是对的。我没有考虑ref/out参数。支持该功能也很好,但是对于我目前的使用,如果这可以简化解决方案的话,我不需要ref/out用法。谢谢你的建议。我对此进行了广泛的尝试(花了一些时间进行了尝试),最终得到了一个采用类似方法的不同解决方案,但它不需要使用表达式树。不确定这是最佳解决方案还是最终解决方案,但它目前起作用,确实回答了我的问题。@Danielrera您的两个链接是相同的,一个是对其他人问题的答案。对于那些我将自己的答案标记为解决方案的问题,就是没有一个完整的答案,我解决了问题,只是为了帮助其他找到问题的人。另外,你链接的那个我标记了我自己的,我提供了用我找到的正确解决方案编辑的,我会将它们标记为解决方案。。不确定你的观点是什么,但如果我做错了什么,请告诉我。:)知道了。当做
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;
    }
}
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);