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