如何通过C#中的类型创建动态委托对象? [英] How to create a dynamic delegate object by type in C#?

查看:163
本文介绍了如何通过C#中的类型创建动态委托对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  var retType = type.GetMethod(Invoke)。ReturnType; 
var obj = Delegate.CreateDelegate(type,delegate(object [] args){
...
if(retType!= typeof(void))
...不知何故创建类型为retType的对象并返回它...
});

显然这不会编译,因为 CreateDelegate 期望一个 MethodInfo 作为第二个参数。如何正确执行此操作?



更新:有关我正在努力实现的更多信息。运行两个应用程序 - 浏览器中的客户端和C#中的服务器。浏览器能够通过将参数序列化为JSON并通过网络发送呼叫(如RPC)来调用服务器端的远程功能。这个功能已经有了,但是我想添加对回调的支持。例如:



JavaScript(客户端):

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

C#(服务器):

  void notifyAboutNewObjects(Action< string> callback){
...
callback(new-object-uuid);
...
}

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



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



Uppdate:我创建了一个小测试程序,演示了我所需要的:

 使用系统; 
使用System.Reflection;

命名空间TestDynamicDelegates
{
class MainClass
{
//测试函数,为此我们需要创建默认参数。
private static string Foobar(float x,Action< int> a1,Func< string,string> a2){
a1(42);
return a2(test);
}

//代表代表泛型函数。
私有委托对象AnyFunc(params object [] args);

//构造一组要传递给函数的默认参数。
private static object [] ConstructParams(ParameterInfo [] paramInfos)
{
object [] methodParams = new object [paramInfos.Length]; (var i = 0; i< paramInfos.Length; i ++)
{
ParameterInfo paramInfo = paramInfos [i];
if(typeof(Delegate).IsAssignableFrom(paramInfo.ParameterType)){
//对于委托类型,我们创建一个映射到通用函数的委托。
键入retType = paramInfo.ParameterType.GetMethod(Invoke)。

//通用函数只会打印参数并创建默认返回值(或返回null
//如果返回类型为void)。
AnyFunc tmpObj = delegate(object [] args){
Console.WriteLine(Invoked dynamic delegate with following parameters:);
(var j = 0; j< args.Length; j ++)
Console.WriteLine({0}:{1},j,args [j]);
if(retType!= typeof(void))
return Activator.CreateInstance(retType);
返回null;
};

//将泛型函数转换为所需的委托类型。
methodParams [i] = / *以某种方式将tmpObj转换为paramInfo.ParameterType * /
} else {
//对于所有其他参数类型,我们创建一个默认值。
methodParams [i] = Activator.CreateInstance(paramInfo.ParameterType);
}
}

return methodParams;
}

public static void Main(string [] args)
{
委托d =(Func< float,Action< int>,Func< string,string> ;,string>)Foobar;

ParameterInfo [] paramInfo = d.Method.GetParameters();
object [] methodParams = ConstructParams(paramInfo);
Console.WriteLine({0} returned:{1},d.Method.Name,d.DynamicInvoke(methodParams));
}
}
}


解决方案

我写了一个开源PCL库,名为 Dynamitey (在nuget中),它可以做各种各样的动态的东西使用C#DLR。



它具体有一个静态方法叫做 Dynamic.CoerceToDelegate(object invokeableObject,Type delegateType)动态调用 DynamicObject 或更一般的委托,使用CompiledExpressions的特定代表类型()。



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

  public class AnyInvokeObject:DynamicObject {
Func< object [],object> _func;
public AnyInvokeObject(Func< object [],object> func){
_func = func;
}
public override bool TryInvoke(InvokeBinder binder,object [] args,out object result){
result = _func(args);
返回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);


Let's say I have a type, which I know to be derived from a Delegate type. I would like to create an object of this type wrapping an anonymous delegate that accepts arbitrary params and returns an object of correct return type:

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 ...
});

Obviously this won't compile, because CreateDelegate expects a MethodInfo as the second argument. How can I do this correctly?

Update: A little more info on what I am trying to achieve. There are two applications running - client in a browser and a server in C#. Browser is able to call remote functions on the server side by serializing arguments to JSON and sending the call over the network (like in RPC). This works already, but I would like to add support for callbacks. For example:

JavaScript (client):

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

C# (server):

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

The middleware code will receive a call from the browser and will need to generate fake callback delegate that will actually send the call to callback back to the browser and block the thread until it completes. The code for sending/receiving is there already, I am just stuck on how to generate a generic delegate that will simply put all arguments into an array and pass them to the sending code.

Update: If someone can write code that will generate such a delegate at runtime (e.g. using DynamicMethod) , I'll consider that a valid answer. I just don't have enough time to learn how to do this and hope that someone experienced will be able to write this code quickly enough. Essentially the code should just take arbitrary delegate params (list and types are available at runtime), put them into an array and call generic method. The generic method will always return an object, which should be cast into respective return type or ignored if the function returns void.

Uppdate: I've created a small test program that demonstrates what I need:

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<int> a1, Func<string, string> 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<int>,Func<string,string>,string>)Foobar;

            ParameterInfo[] paramInfo = d.Method.GetParameters();
            object[] methodParams = ConstructParams(paramInfo);
            Console.WriteLine("{0} returned: {1}", d.Method.Name, d.DynamicInvoke(methodParams));
        }
    }
}

解决方案

I wrote a opensource PCL library, called Dynamitey (in nuget), that does all sorts of dynamic things using the C# DLR. .

It specifically has a static method called Dynamic.CoerceToDelegate(object invokeableObject, Type delegateType) That basically wraps the dynamic invocation of a DynamicObject or a more general delegate, with the specific Type of delegate using CompiledExpressions (source).

using System.Dynamic you can create an invokable object:

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

Then in your sample:

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);

这篇关于如何通过C#中的类型创建动态委托对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆