C# передать любой метод в качестве параметра - PullRequest
0 голосов
/ 28 апреля 2020

Я делаю сетевое приложение, в котором хочу реализовать строго типизированный RP C. В результате я хотел бы иметь возможность передавать методы независимо от параметров, чтобы я мог получить их и сохранить их в словаре, чтобы я мог правильно составлять параметры запроса и после получения пакета, я могу читать его, используя параметры тот же метод удаленного доступа

Я бы хотел что-то вроде этого:

Register(Enum key, [method with unknown parameters])

Ответы [ 3 ]

1 голос
/ 28 апреля 2020

Как уже упоминалось выше, вы можете использовать MethodInfo , оно принадлежит пространству имен System.Reflection. Для этого сначала получите тип объекта Type, например:

var type = obj.GetType ()

После этого вы можете использовать var methods = type.GetMethods(). Это даст вам MethodInfo []. Поиск элемента, используя ваш любимый метод для этого. Например, Linq:

var method = methods.Where(it => it.Name == __yourName__).LastOrDefault();

*, где yourName - это имя вашего метода.

Теперь у вас есть метод, который вы ищете. Получите параметры , используя

var parameters = method.getParameters();

И есть параметры как ParameterInfo[]. Оттуда вы можете получить тип каждого параметра, используя свойство parameter.ParameterType.

Это очень осторожно с Reflection, оно очень, очень мощное, но может сильно снизить производительность при чрезмерном использовании.

Посмотрите на это System.Reflection Пространство имен здесь .

Теперь вы можете добавить метод в коллекцию, например словарь:

var dictionary = new Dictionary<int,MethodInfo>();
dictionary.Add(1, method);

И получить его следующим образом:

var method = dictionary[1];

Для вызова функции вы можете использовать method.Invoke() и передать параметры по мере необходимости.

РЕДАКТИРОВАТЬ: Если вы также хотите отправить параметры как функция по сети. Вы можете создать новый класс, который будет служить объектом передачи данных DTO. Этот класс может иметь в качестве свойства массив параметров (ParameterInfo []), MethodInfo и все, что вам нужно.

Затем вы можете сериализовать объект (возможно, json) и отправить его в другую систему, чтобы может затем десериализовать его и вызвать методInfo obj

1 голос
/ 28 апреля 2020

В 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
    }
}
0 голосов
/ 28 апреля 2020
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
    }
}
...