【发布时间】:2013-01-28 06:05:56
【问题描述】:
我试图通过提供使用泛型的工厂/构建器来抽象出我的接口实现。但是,我在运行时遇到了多个调度和 C# 泛型的问题,这看起来很奇怪。
基本场景是我定义了几个接口:
public interface IAddressModel
{
}
public interface IUserModel
{
}
然后我有一个工厂类来返回实际的实现:
public class Factory
{
public T BuildModel<T>()
{
return BuildModel(default(T));
}
public object BuildModel(object obj)
{
//this is here because the compiler will complain about casting T to
//the first inteface parameter in the first defined BuildModel method
return null;
}
public IAddressModel BuildModel(IAddressModel iModel)
{
//where AddressModel inherits from IAddressModel
return new AddressModel();
}
public IUserModel BuildModel(IUserModel iModel)
{
//where UserModel inherits from IUserModel
return new UserModel();
}
}
问题是当工厂被这样调用时:new Factory().BuildModel<IAddressModel>()
在运行时从泛型分派的 BuildModel(...) 方法始终是 T 的最小派生形式,在这种情况下始终是对象。
但是,如果您调用new Factory().BuildModel(default(IAddressModel));,则会调度正确的方法(很可能是因为这是在编译时完成的)。似乎使用泛型的动态分派不会检查最派生类型的方法,即使调用的方法应该是相同的,无论它是在编译时还是运行时完成。理想情况下,我想将 BuildModel(...) 方法设为私有,并且只公开通用方法。是否有另一种方法可以让动态调度在运行时调用正确的方法?我尝试将 BuildModel<>() 实现更改为 return BuildModel((dynamic)default(T)) 但这会引发运行时错误,即无法确定要分派的方法。有没有办法通过逆变和更多接口来做到这一点?
【问题讨论】:
-
你考虑过
new Factory<IAddressModel>().BuildModel()吗? -
@Bobson - 是的,我尝试将泛型移动到类级别而不是方法级别,这与运行时调度没有任何区别。
-
我不认为这是运行时与编译时的问题。据我所知,除非您使用
dynamic,否则泛型都在编译时解析,就像常规类型一样。而且您不能使用dynamic,因为default(T)将是null,因此它无法确定它应该是什么。我怀疑这就是为什么工厂的标准是使用switch...
标签: c# generics dynamic-dispatch multiple-dispatch