处理泛型
本文关键字:泛型 处理 | 更新日期: 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
等
然而,至少有两种方法可以解决这种情况:
- 通过向
Order
及其子类添加Accept
方法来使用访问者模式,或者 - 通过使用
dynamic
,在这种情况下,运行时将执行正确的调度。
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);
然后你可以分配任何唯一的属性给给定的派生类。