Сохраните метод generi c + тип arg + тип возврата внутри списка, чтобы вызвать его позже - PullRequest
0 голосов
/ 30 марта 2020

Я пытаюсь заархивировать что-то вроде «метода регистрации для определенного события» с разными типами аргументов и типами возврата, так что мой план работал с обобщениями.

После вызова нужной мне функции RegisterMethod хранить заданный аргумент метода внутри списка, включая его тип ввода и тип вывода. Для дальнейшего использования я хочу вызвать данный метод с зарегистрированными типами.

Теперь у меня возникает следующая проблема: после вызова ProcessIncomingRequest на сервере мне нужно десериализовать данные byte [] на данный тип i определен в методе RegisterMethod, а также тип возвращаемого значения для ответа клиенту. Но я не знаю, как привести эти типы в код.

struct MethodData
{
    public string Name;
    public System.Reflection.MethodInfo MethodInfo;
    public Type ReturnType;
    public Type ArgumentType;
}

class NetworkServer
{
    List<MethodData> list = new List<MethodData>();
    public void RegisterMethod<In, Out>(string name, Func<NetworkClient, In, Out> method)
    {
        list.Add(new MethodData()
        {
            MethodInfo = method.Method,
            Name = name,
            ReturnType = typeof(Out),
            ArgumentType = typeof(In)
        });

        // Store the method including 
        // it the return type
        // In theory I want to add them to a List/Dictionary
        // and re-use the method + types in the
        // ProcessIncomingRequest method.
    }

    public void RegisterMethod<In>(string name, Action<NetworkClient, In> method)
    {
        list.Add(new MethodData()
        {
            MethodInfo = method.Method,
            Name = name,
            ArgumentType = typeof(In),
        });
        // Same as above, this method doesn't return anything. Its just a call and forget
    }

    public static void ProcessIncomingRequest(NetworkClient cl, string name, byte[] data)
    {
        var method = list.SingleOrDefault(x => x.Name.Equals(name));

        if(method != NULL)
        {
            var finalData = Serializer<Tin>(data);
            // Tin = it.ArgumentType
            // Tout = it.ReturnType
            // This is exactly what I would need to archive

            var retn = it.MethodInfo.Invoke(null, new[] { cl, finalData });
            if(retn != NULL && it.ReturnType != NULL)
                cl.Send<Tout>(retn);
        }

        // name represents the method name in the List
        // data represents represents the parameter values
        // The generic "Tin" and "Tout is the problem here
    }
}


static void main()
{
    NetworkServer server = new NetworkServer(9000);
    server.RegisterMethod<int, bool>("CheckValue", CheckValue);
    server.RegisterMethod<string>("Log", NotifyLogger);
    server.Start();
}


// Execute method with received data and return result to client
static bool CheckValue(NetworkClient cl, int value)
{
    return value >= 10;
}


// Execute data without the need of any return
static void NotifyLogger(NetworkClient cl, string logger)
{
    Console.WriteLine($"Incoming Logger request : {logger}");
    MyLogger.Write($"[SERVER] {logger}");
}

1 Ответ

0 голосов
/ 30 марта 2020

Если вы хотите вызвать метод, который принимает обобщенный c параметр типа с объектом типа, вам необходимо использовать отражение.

Некоторые библиотеки сериализации имеют методы десериализации, которые принимают объекты типа вместо универсального параметра типа c, и сериализуют методы, которые просто принимают объект. Если бы такие методы были доступны, я бы предпочел такое решение над отражением magi c.

...