Как динамически вызывать методы в зависимости от фактического типа среды выполнения? - PullRequest
0 голосов
/ 05 июня 2019

Я получаю JSON из внешнего источника (с информацией о типе в нем), который я десериализую с помощью JSON.NET

JsonSerializerSettings settings = new JsonSerializerSettings(); 
settings.TypeNameHandling = TypeNameHandling.All;
//because the type info is included 'obj' will be of type Foo, Bar, Baz, etc
var obj = JsonConvert.DeserializeObject(jsonString, settings); 

Я также получаю тип команды, которую мне нужно выполнить на объекте (например, «Отправить», «Получить», «Удалить» и т. Д.). Я использую это, чтобы вызвать правильный метод на службе. Служба определяет свои методы для каждого типа в этом формате (примечание: я не поддерживаю службу, я просто называю ее):

///where T has an implementation for each type (Foo, Bar, etc)
T Send(T objToSend)
T Retrieve (T objToRet)
T Remove (T objToRemove)

так например:

Foo f = service.Send(aFoo);
Bar b = service.Send(aBar);
Foo f2 = service.Retrieve(aFoo);
Bar b2 = service.Retrieve(aBar);

есть ли более элегантный способ сделать это, кроме большого оператора switch и блоков if-else для каждого типа? Это будет работать, но кажется действительно неуклюжим, и если мы продолжим добавлять типы, это только приведет к более грубому

switch(command){
    case "Send":
        if(obj is Foo){
            service.Send((Foo)obj);
        }
        if(obj is Bar){
            service.Send((Bar)obj);
        }
        if(obj is Baz){
            service.Send((Baz)obj);
        }
    break;
    case "Retrieve":
    //etc...
    case "Remove":
    //etc...
}

спасибо за любые идеи, которые вы можете предоставить

1 Ответ

0 голосов
/ 05 июня 2019

Вы можете использовать relfection для достижения этой цели. Даны следующие классы:

public class Bar
{
}

public class Foo
{
}

public class Service
{
    public Bar Send(Bar objToSend)
    {
        Console.WriteLine("Send Bar");
        return objToSend;
    }

    public Foo Send(Foo objToSend)
    {
        Console.WriteLine("Send Foo");
        return objToSend;
    }
}

Позвоните в службу следующим образом:

// This is the object we received and need to process
var obj = new Bar();

// This is the method we need to execute
string method = "Send";

// Initialize a new service and get its type
var service = new Service();
Type serviceType = service.GetType();

// Get the correct method by looking at the method name and the parameter type
MethodInfo methodInfo = serviceType.GetMethods().FirstOrDefault(x => x.Name == method && x.GetParameters()[0].ParameterType == obj.GetType());

// Invoke the method
object returnObj = methodInfo.Invoke(service, new object[] { obj });

Если вы вообще заботитесь о производительности, я рекомендую не использовать этот подход и просто использовать вместо него переключатель.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...