C#将任何方法作为参数传递

C#将任何方法作为参数传递,c#,networking,reflection,rpc,C#,Networking,Reflection,Rpc,我正在制作一个网络应用程序,希望在其中实现强类型RPC。因此,无论参数是什么,我都希望能够传递方法,这样我就可以获取它们并将它们存储在字典中,这样我就可以正确地构造请求参数,而且一旦数据包到达,我就能够使用使用相同的远程方法读取它 我想要这样的东西: Register(Enum key, [method with unknown parameters]) var method = dictionary[1]; using System; using System.Collections.Ge

我正在制作一个网络应用程序,希望在其中实现强类型RPC。因此,无论参数是什么,我都希望能够传递方法,这样我就可以获取它们并将它们存储在字典中,这样我就可以正确地构造请求参数,而且一旦数据包到达,我就能够使用使用相同的远程方法读取它

我想要这样的东西:

Register(Enum key, [method with unknown parameters])
var method = dictionary[1];
using System;
using System.Collections.Generic;

namespace ConsoleApp
{

    public class Program
    {
        public static void Main(params string[] args)
        {
            var app = new NetworkingApplication();
            app.Register<Action<int, string>>(PacketType.Type1, Method1, 1, "string1 argument");
            app.Register<Func<string, string>>(PacketType.Type2, Method2, "string2 argument");
            app.OnPacketReceived(PacketType.Type1);
            app.OnPacketReceived(PacketType.Type2);
        }

        public static void Method1(int arg1, string arg2)
        {
            Console.WriteLine($"Method1 Invoked with args: {arg1}, {arg2}");
        }

        public static string Method2(string arg1)
        {
            Console.WriteLine($"Method2 Invoked with args: {arg1}");
            return "Foo";
        }
    }

    public class NetworkingApplication
    {
        private readonly IDictionary<PacketType, DelegateInvoker> _registrations;

        public NetworkingApplication()
        {
            _registrations = new Dictionary<PacketType, DelegateInvoker>();
        }

        public void Register<TDelegate>(PacketType packetType, TDelegate @delegate, params object[] args)
            where TDelegate : Delegate
        {
            _registrations[packetType] = new DelegateInvoker(@delegate, args);
        }

        //invoke this when the packet is received
        public void OnPacketReceived(PacketType type)
        {
            if (_registrations.TryGetValue(type, out var invoker))
            {
                invoker.Invoke();
            }
        }

        private class DelegateInvoker
        {
            public DelegateInvoker(Delegate @delegate, object[] args)
            {
                Delegate = @delegate;
                Arguments = args;
            }

            private Delegate Delegate { get; }
            private object[] Arguments { get; }

            public void Invoke()
            {
                Delegate.Method.Invoke(Delegate.Target, Arguments);
            }
        }
    }





    public enum PacketType
    {
        Type1,
        Type2,
        Type3
    }
}
使用系统;
使用System.Collections.Generic;
使用系统线程;
使用System.Threading.Tasks;
名称空间控制台
{
公共课程
{
公共静态void Main(参数字符串[]args)
{
var app=新的网络应用程序();
应用程序注册表(PacketType.Type1,()=>
{
WriteLine(“接收到类型1数据包!”);
});
}
}
公共类网络应用程序
{
私人只读词典注册;
公共网络应用程序()
{
_注册=新字典();
}
公共无效寄存器(PacketType PacketType,操作方法)
{
_注册[packetType]=方法;
}
//在接收到数据包时调用此函数
PacketReceived上的公共无效(PacketType类型)
{
if(_registrations.TryGetValue(类型,输出var动作))
{
action?.Invoke();
}
}
}
公共枚举包类型
{
类型1,类型2,类型3
}
}

如上所述,您可以使用它,它属于
System.Reflection
命名空间。为此,首先获取对象的
类型,如下所示:

Register(Enum key, [method with unknown parameters])
var method = dictionary[1];
using System;
using System.Collections.Generic;

namespace ConsoleApp
{

    public class Program
    {
        public static void Main(params string[] args)
        {
            var app = new NetworkingApplication();
            app.Register<Action<int, string>>(PacketType.Type1, Method1, 1, "string1 argument");
            app.Register<Func<string, string>>(PacketType.Type2, Method2, "string2 argument");
            app.OnPacketReceived(PacketType.Type1);
            app.OnPacketReceived(PacketType.Type2);
        }

        public static void Method1(int arg1, string arg2)
        {
            Console.WriteLine($"Method1 Invoked with args: {arg1}, {arg2}");
        }

        public static string Method2(string arg1)
        {
            Console.WriteLine($"Method2 Invoked with args: {arg1}");
            return "Foo";
        }
    }

    public class NetworkingApplication
    {
        private readonly IDictionary<PacketType, DelegateInvoker> _registrations;

        public NetworkingApplication()
        {
            _registrations = new Dictionary<PacketType, DelegateInvoker>();
        }

        public void Register<TDelegate>(PacketType packetType, TDelegate @delegate, params object[] args)
            where TDelegate : Delegate
        {
            _registrations[packetType] = new DelegateInvoker(@delegate, args);
        }

        //invoke this when the packet is received
        public void OnPacketReceived(PacketType type)
        {
            if (_registrations.TryGetValue(type, out var invoker))
            {
                invoker.Invoke();
            }
        }

        private class DelegateInvoker
        {
            public DelegateInvoker(Delegate @delegate, object[] args)
            {
                Delegate = @delegate;
                Arguments = args;
            }

            private Delegate Delegate { get; }
            private object[] Arguments { get; }

            public void Invoke()
            {
                Delegate.Method.Invoke(Delegate.Target, Arguments);
            }
        }
    }





    public enum PacketType
    {
        Type1,
        Type2,
        Type3
    }
}
var type=obj.GetType()

在此之后,您可以使用
var methods=type.GetMethods()
。这将为您提供MethodInfo[]。使用您最喜欢的方法搜索元素。例如Linq:

var method = methods.Where(it => it.Name == __yourName__).LastOrDefault();
*其中,yourName是方法的名称

现在你有了你想要的方法。使用

还有一些参数是
ParameterInfo[]
。 从中可以使用parameter.ParameterType属性获取每个参数的类型

也就是说,对反射要非常小心,它非常非常强大,但过度使用时会严重降低性能

请查看它
System.Reflection
namespace

现在可以将该方法添加到集合中,例如字典:

var dictionary = new Dictionary<int,MethodInfo>();
dictionary.Add(1, method);
要调用该函数,您可以使用
method.Invoke()
并根据需要传递参数

编辑: 如果您希望通过网络发送参数和函数。您可以创建一个用作DTO数据传输对象的新类。这个类可以有一个参数数组(ParameterInfo[])、MethodInfo和您想要的任何东西作为属性

然后,您可以序列化对象(可能是json)并将其发送到另一个系统,然后该系统可以对其进行反序列化,并使用泛型和委托约束调用C#8.0中的MethodInfo obj。您可以执行以下操作:

Register(Enum key, [method with unknown parameters])
var method = dictionary[1];
using System;
using System.Collections.Generic;

namespace ConsoleApp
{

    public class Program
    {
        public static void Main(params string[] args)
        {
            var app = new NetworkingApplication();
            app.Register<Action<int, string>>(PacketType.Type1, Method1, 1, "string1 argument");
            app.Register<Func<string, string>>(PacketType.Type2, Method2, "string2 argument");
            app.OnPacketReceived(PacketType.Type1);
            app.OnPacketReceived(PacketType.Type2);
        }

        public static void Method1(int arg1, string arg2)
        {
            Console.WriteLine($"Method1 Invoked with args: {arg1}, {arg2}");
        }

        public static string Method2(string arg1)
        {
            Console.WriteLine($"Method2 Invoked with args: {arg1}");
            return "Foo";
        }
    }

    public class NetworkingApplication
    {
        private readonly IDictionary<PacketType, DelegateInvoker> _registrations;

        public NetworkingApplication()
        {
            _registrations = new Dictionary<PacketType, DelegateInvoker>();
        }

        public void Register<TDelegate>(PacketType packetType, TDelegate @delegate, params object[] args)
            where TDelegate : Delegate
        {
            _registrations[packetType] = new DelegateInvoker(@delegate, args);
        }

        //invoke this when the packet is received
        public void OnPacketReceived(PacketType type)
        {
            if (_registrations.TryGetValue(type, out var invoker))
            {
                invoker.Invoke();
            }
        }

        private class DelegateInvoker
        {
            public DelegateInvoker(Delegate @delegate, object[] args)
            {
                Delegate = @delegate;
                Arguments = args;
            }

            private Delegate Delegate { get; }
            private object[] Arguments { get; }

            public void Invoke()
            {
                Delegate.Method.Invoke(Delegate.Target, Arguments);
            }
        }
    }





    public enum PacketType
    {
        Type1,
        Type2,
        Type3
    }
}
使用系统;
使用System.Collections.Generic;
名称空间控制台
{
公共课程
{
公共静态void Main(参数字符串[]args)
{
var app=新的网络应用程序();
应用寄存器(PacketType.Type1,Method1,1,“string1参数”);
应用寄存器(PacketType.Type2,Method2,“string2参数”);
收到应用程序OnPacketReceived(PacketType.Type1);
收到应用程序OnPacketReceived(PacketType.Type2);
}
公共静态void方法1(int arg1,字符串arg2)
{
WriteLine($”Method1用args调用:{arg1},{arg2}”);
}
公共静态字符串方法2(字符串arg1)
{
WriteLine($“Method2用args:{arg1}调用”);
返回“Foo”;
}
}
公共类网络应用程序
{
私人只读词典注册;
公共网络应用程序()
{
_注册=新字典();
}
公共无效寄存器(PacketType PacketType,TDelegate@delegate,params object[]args)
其中TDelegate:委托
{
_注册[packetType]=新的DelegateInvoker(@delegate,args);
}
//在接收到数据包时调用此函数
PacketReceived上的公共无效(PacketType类型)
{
if(_registrations.TryGetValue(类型,out var invoker))
{
invoker.Invoke();
}
}
私有类委托调用程序
{
公共DelegateInvoker(Delegate@Delegate,对象[]args)
{
Delegate=@Delegate;
参数=args;
}
私有委托{get;}
私有对象[]参数{get;}
公共无效调用()
{
Delegate.Method.Invoke(Delegate.Target,参数);
}
}
}
公共枚举包类型
{
类型1,
类型2,
类型3
}
}

第一段的用法非常混乱(至少对我来说是这样)。你能不能再多加几句话来描述一下你想做什么?“网络应用程序”部分相关吗?这不是我的主要目的,本质上我只是想要一个方法,它可以获取你传递给它的任何方法的参数类型,类似于MyMethod(Action)但是,如果动作可以有任何种类和数量的参数,这些参数会显示出不起作用的代码,这样我们就可以帮助解决具体问题。你是有意推出自己的品种,还是仅仅使用gRPC之类的工具对你有好处?是的,这是我目前拥有的,但我需要能够通过任何类型的方法(参数方面)您可以在acti中封装任何喜欢的方法,而不是action