如何通过C#中的类型创建动态委托对象?

假设我有一个type ,我知道它是从Delegate类型派生的。 我想创建一个这种类型的对象包装一个匿名委托,它接受任意参数并返回一个正确返回类型的对象:

 var retType = type.GetMethod("Invoke").ReturnType; var obj = Delegate.CreateDelegate(type, delegate(object[] args) { ... if (retType != typeof(void)) ... somehow create object of type retType and return it ... }); 

显然这不会编译,因为CreateDelegate期望一个MethodInfo作为第二个参数。 我该怎么做才能正确?

更新:关于我想要达到的目标的更多信息。 运行了两个应用程序 – 浏览器中的客户端和C#中的服务器。 浏览器能够通过将参数序列化为JSON并通过网络发送呼叫(如RPC)来调用服务器端的远程function。 这已经有效,但我想添加对回调的支持。 例如:

JavaScript(客户端):

 function onNewObject(uuid) { console.log(uuid); } server.notifyAboutNewObjects(onNewObject); 

C#(服务器):

 void notifyAboutNewObjects(Action callback) { ... callback("new-object-uuid"); ... } 

中间件代码将接收来自浏览器的调用,并且需要生成假callback委托,该委托实际上将调用callback发送回浏览器并阻塞线程直到完成。 发送/接收的代码已经存在,我只是坚持如何生成一个通用委托,它将简单地将所有参数放入一个数组并将它们传递给发送代码。

更新:如果有人可以编写将在运行时生成此类委托的代码(例如,使用DynamicMethod ),我会认为这是一个有效的答案。 我只是没有足够的时间来学习如何做到这一点,并希望有经验的人能够足够快地编写这段代码。 本质上,代码应该只使用任意委托参数(列表和类型在运行时可用),将它们放入数组并调用generics方法。 generics方法将始终返回一个object ,该object应该转换为相应的返回类型,或者如果函数返回void则忽略该对象。

Uppdate:我已经创建了一个小型测试程序来演示我需要的东西:

 using System; using System.Reflection; namespace TestDynamicDelegates { class MainClass { // Test function, for which we need to create default parameters. private static string Foobar(float x, Action a1, Func a2) { a1(42); return a2("test"); } // Delegate to represent generic function. private delegate object AnyFunc(params object[] args); // Construct a set of default parameters to be passed into a function. private static object[] ConstructParams(ParameterInfo[] paramInfos) { object[] methodParams = new object[paramInfos.Length]; for (var i = 0; i < paramInfos.Length; i++) { ParameterInfo paramInfo = paramInfos[i]; if (typeof(Delegate).IsAssignableFrom(paramInfo.ParameterType)) { // For delegate types we create a delegate that maps onto a generic function. Type retType = paramInfo.ParameterType.GetMethod("Invoke").ReturnType; // Generic function that will simply print arguments and create default return value (or return null // if return type is void). AnyFunc tmpObj = delegate(object[] args) { Console.WriteLine("Invoked dynamic delegate with following parameters:"); for (var j = 0; j < args.Length; j++) Console.WriteLine(" {0}: {1}", j, args[j]); if (retType != typeof(void)) return Activator.CreateInstance(retType); return null; }; // Convert generic function to the required delegate type. methodParams[i] = /* somehow cast tmpObj into paramInfo.ParameterType */ } else { // For all other argument type we create a default value. methodParams[i] = Activator.CreateInstance(paramInfo.ParameterType); } } return methodParams; } public static void Main(string[] args) { Delegate d = (Func<float, Action,Func,string>)Foobar; ParameterInfo[] paramInfo = d.Method.GetParameters(); object[] methodParams = ConstructParams(paramInfo); Console.WriteLine("{0} returned: {1}", d.Method.Name, d.DynamicInvoke(methodParams)); } } } 

我编写了一个名为Dynamitey (在nuget中)的开源PCL库,它使用C#DLR完成各种动态操作。 。

它特别有一个名为Dynamic.CoerceToDelegate(object invokeableObject, Type delegateType)的静态方法Dynamic.CoerceToDelegate(object invokeableObject, Type delegateType)它基本上使用CompiledExpressions( source )包含DynamicObject或更一般委托的动态调用,具有特定的委托类型。

使用System.Dynamic,您可以创建一个可调用的对象:

 public class AnyInvokeObject:DynamicObject{ Func _func; public AnyInvokeObject(Func func){ _func = func; } public override bool TryInvoke(InvokeBinder binder, object[] args, out object result){ result = _func(args); return true; } } 

然后在你的样本中:

 var tmpObj = new AnyInvokeObject(args => { Console.WriteLine("Invoked dynamic delegate with following parameters:"); for (var j = 0; j < args.Length; j++) Console.WriteLine(" {0}: {1}", j, args[j]); if (retType != typeof(void)) return Activator.CreateInstance(retType); return null; }); methodParams[i] = Dynamic.CoerceToDelegate(tmpObj, paramInfo.ParameterType); 

没有代表的解决方案怎么样? (警告:猖獗的伪代码)

 class AbstractServerToClientMessage { public virtual string ToJSON(); } class OnNewObjectMessage: AbstractServerToClientMessage {...} class OnSomethingElseHappenedMessage: AbstractServerToClientMessage {...} void NotifyClient(AbstractServerToClientMessage message) event OnNewObject; event OnSomethingElseHappened; void notifyAboutNewObjects() { ... OnNewObject += NotifyClient; ... } void AddNewObject(SomeObject obj) { OnNewObjectMessage message(obj); OnNewObject(message); // actually add the object } 

消息无论如何都会被序列化,为什么要这么麻烦? 多态性将照顾其余部分。 唯一的要求是拥有一组与每种事件类型相对应的消息。

可以通过写入AbstractServerToClientMessage某个字段来实现返回值。


或者,您实际上可以拥有一个具有固定签名的委托,该委托接受类似的AbstractServerToClientMessage 。 同样,多态性(+反序列化的类工厂)将允许将其转换为正确的消息类型。

您可以查看SignalR的源代码,也可以直接使用它。

在服务器可以调用的浏览器中注册一个函数

 var connection = $.hubConnection(); var yourHubProxy = connection.createHubProxy('yourHub'); yourHubProxy.on('addMessageToConsole', function (message) { console.log(message); }); 

并在服务器上

 public class YourHub : Hub { public void SendMessage(string message) { Clients.All.addMessageToConsole(message); } } 

有关更多示例,请参见此处