C# 将任何方法作为参数传递
C# Pass any method as parameter
我正在制作一个网络应用程序,我想在其中实施强类型 RPC。因此,我希望无论参数如何都能传递方法,这样我就可以获取它们并将它们存储在字典中,这样我就可以正确地构造请求参数,一旦数据包到达,我就可以使用参数读取它使用相同的远程方法
我想要这样的东西:
Register(Enum key, [method with unknown parameters])
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp
{
public class Program
{
public static void Main(params string[] args)
{
var app = new NetworkingApplication();
app.Register(PacketType.Type1, () =>
{
Console.WriteLine("Type1 Packet is received!");
});
}
}
public class NetworkingApplication
{
private readonly IDictionary<PacketType, Action> _registrations;
public NetworkingApplication()
{
_registrations = new Dictionary<PacketType, Action>();
}
public void Register(PacketType packetType, Action method)
{
_registrations[packetType] = method;
}
//invoke this when the packet is received
public void OnPacketReceived(PacketType type)
{
if (_registrations.TryGetValue(type, out var action))
{
action?.Invoke();
}
}
}
public enum PacketType
{
Type1,Type2,Type3
}
}
上面提到可以使用MethodInfo,它属于System.Reflection
命名空间。为此,首先像这样获取对象的 Type
类型:
var 类型 = obj.GetType()
之后你可以使用var methods = type.GetMethods()
。这将为您提供 MethodInfo[]。使用您最喜欢的方法搜索元素。如Linq:
var method = methods.Where(it => it.Name == __yourName__).LastOrDefault();
*其中 您的姓名 是您的方法的名称。
现在您找到了想要的方法。使用
获取 parameters
var parameters = method.getParameters();
还有参数ParameterInfo[]
。
从那里您可以使用 parameter.ParameterType 属性.
获取每个参数的类型
这就是说要非常小心反射,它非常非常强大,但如果过度使用会严重降低性能。
看看它 System.Reflection
命名空间 here .
您现在可以将方法添加到集合中,例如字典:
var dictionary = new Dictionary<int,MethodInfo>();
dictionary.Add(1, method);
然后像这样检索它:
var method = dictionary[1];
要调用该函数,您可以使用 method.Invoke()
并根据需要传入参数。
编辑:
如果您想通过网络发送参数和功能。您可以创建一个新的 class 作为 DTO 数据传输对象。 class 可以有一个参数数组 (ParameterInfo[])、MethodInfo 和您想要的任何其他内容。属性。
然后您可以序列化对象(可能 json)并将其发送到另一个系统,然后反序列化它,并调用 MethodInfo obj
在使用泛型和委托约束的 C# 8.0 中,您可以执行如下操作:
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
}
}
我正在制作一个网络应用程序,我想在其中实施强类型 RPC。因此,我希望无论参数如何都能传递方法,这样我就可以获取它们并将它们存储在字典中,这样我就可以正确地构造请求参数,一旦数据包到达,我就可以使用参数读取它使用相同的远程方法
我想要这样的东西:
Register(Enum key, [method with unknown parameters])
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp
{
public class Program
{
public static void Main(params string[] args)
{
var app = new NetworkingApplication();
app.Register(PacketType.Type1, () =>
{
Console.WriteLine("Type1 Packet is received!");
});
}
}
public class NetworkingApplication
{
private readonly IDictionary<PacketType, Action> _registrations;
public NetworkingApplication()
{
_registrations = new Dictionary<PacketType, Action>();
}
public void Register(PacketType packetType, Action method)
{
_registrations[packetType] = method;
}
//invoke this when the packet is received
public void OnPacketReceived(PacketType type)
{
if (_registrations.TryGetValue(type, out var action))
{
action?.Invoke();
}
}
}
public enum PacketType
{
Type1,Type2,Type3
}
}
上面提到可以使用MethodInfo,它属于System.Reflection
命名空间。为此,首先像这样获取对象的 Type
类型:
var 类型 = obj.GetType()
之后你可以使用var methods = type.GetMethods()
。这将为您提供 MethodInfo[]。使用您最喜欢的方法搜索元素。如Linq:
var method = methods.Where(it => it.Name == __yourName__).LastOrDefault();
*其中 您的姓名 是您的方法的名称。
现在您找到了想要的方法。使用
获取 parametersvar parameters = method.getParameters();
还有参数ParameterInfo[]
。
从那里您可以使用 parameter.ParameterType 属性.
这就是说要非常小心反射,它非常非常强大,但如果过度使用会严重降低性能。
看看它 System.Reflection
命名空间 here .
您现在可以将方法添加到集合中,例如字典:
var dictionary = new Dictionary<int,MethodInfo>();
dictionary.Add(1, method);
然后像这样检索它:
var method = dictionary[1];
要调用该函数,您可以使用 method.Invoke()
并根据需要传入参数。
编辑: 如果您想通过网络发送参数和功能。您可以创建一个新的 class 作为 DTO 数据传输对象。 class 可以有一个参数数组 (ParameterInfo[])、MethodInfo 和您想要的任何其他内容。属性。
然后您可以序列化对象(可能 json)并将其发送到另一个系统,然后反序列化它,并调用 MethodInfo obj
在使用泛型和委托约束的 C# 8.0 中,您可以执行如下操作:
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
}
}