处理泛型

本文关键字:泛型 处理 | 更新日期: 2023-09-27 17:51:12

class Order { ... }
class OrderA : Order { ... }
class OrderB : Order { ... }
class OrderC : Order { ... }
class OrderD : Order { ... }

private Order GetOrder() { ... }

我怎么能有一个方法来动态地将返回的Order对象强制转换为任何特定的对象呢?

private T GetSpecificOrder<T>(T order) : where T : Order
{
    ...
}

我想这样命名它:

var myOrder = GetOrder();
var specificOrder = GetSpecificOrder<Order>(myOrder);
HandleOrder(specificOrder);

我希望这个specificOrder对象被实例化为一个子类,所以我可以这样调用它:

HandleOrder(OrderA o) { ... }
HandleOrder(OrderB o) { ... }
HandleOrder(OrderC o) { ... }
HandleOrder(OrderD o) { ... }

我做错了什么?

处理泛型

听起来您希望在执行时进行重载解析。这是不会发生的……除非您使用dynamic,这可能是最简单的解决方案:

dynamic order = GetOrder(orderId);
HandleOrder(order); // The right overload will be picked at execution time

另一种选择是使用双重调度/访问者模式,但我个人认为这有点笨拙。

另一种选择是使Dictionary<Type, Action<Order>>像这样:

private static readonly Dictionary<Type, Action<Order>> orderHandlers = 
    new Dictionary<Type, Action<Order>>
{
    { typeof(OrderA), order => HandleOrder((OrderA) order) },
    { typeof(OrderB), order => HandleOrder((OrderB) order) },
    { typeof(OrderC), order => HandleOrder((OrderC) order) },
    { typeof(OrderD), order => HandleOrder((OrderD) order) },
};

然后获取相关的委托并调用它:

orderHandlers[order.GetType()](order);

对于泛型不能这样做:尖括号中的内容必须是编译时已知的类型,所以这一行

var specificOrder = GetSpecificOrder<Order>(myOrder);

将需要铸造成为OrderA, OrderB

然而,至少有两种方法可以解决这种情况:

  1. 通过向Order及其子类添加Accept方法来使用访问者模式,或者
  2. 通过使用dynamic,在这种情况下,运行时将执行正确的调度。
下面是如何实现#1:
interface IOrderHandler {
    void HandleOrder(OrderA o);
    void HandleOrder(OrderB o);
    void HandleOrder(OrderC o);
    void HandleOrder(OrderD o);
}
abstract class Order { abstract void Accept(IOrderHandler h); }
class OrderA : Order { void Accept(IOrderHandler h) {h.HandleOrder(this);} }
class OrderB : Order { void Accept(IOrderHandler h) {h.HandleOrder(this);} }
class OrderC : Order { void Accept(IOrderHandler h) {h.HandleOrder(this);} }
class OrderD : Order { void Accept(IOrderHandler h) {h.HandleOrder(this);} }
...
var myOrder = GetOrder();
IOrderHandler handler = ... // Obtain the handler
myOrder.Accept(handler);    // This will call the correct HandleOrder
下面是如何实现#2:
dynamic myOrder = GetOrder();
HandleOrder(myOrder); // Will dispatch based on the runtime type

试试这个…

private T GetSpecificOrder<T>(T order)
    {
     return (T)Convert.ChangeType(T, typeof(T));
    }

您需要调用GetSpecificOrder作为所需的派生类:

var specificOrder = GetSpecificOrder<OrderA>(myOrder);

或者强制转换:

var specificOrder = (OrderA)GetSpecificOrder<Order>(myOrder);

然后你可以分配任何唯一的属性给给定的派生类。