【问题标题】:How do I invoke methods dynamically based on the actual runtime type?如何根据实际运行时类型动态调用方法?
【发布时间】:2019-10-21 01:18:25
【问题描述】:

我从外部源(其中包含类型信息)接收 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...
}

感谢您提供的任何见解

【问题讨论】:

  • 我猜dynamic 会起作用,但当然也有一些取舍。
  • 可以修改Foo,Bar吗? Send 路由可以通过接口完成。对于路由命令类型,您仍然需要switch/caseif 或带有键的东西(例如字典)。
  • 如果你可以像 Sinatr 建议的那样使用接口,那将是最优雅的方式。否则,您可以使用反射。
  • 在您的代码中是否还有其他地方需要将Foo 的引用输入为Foo 并将Bar 的引用输入为Bardynamic 的运行时重载决议很诱人,但我可能只是通过反射来做到这一点。

标签: c# .net architecture


【解决方案1】:

您可以使用 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 });

如果您完全关心性能,我建议您不要使用这种方法,而只需使用开关。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-05
    • 1970-01-01
    • 2011-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-26
    • 1970-01-01
    相关资源
    最近更新 更多