发现泛型约束不能被衍生到它的衍生类型是非常令人费解的。
假设我有以下代码:
public abstract class BaseClass
{
public int Version
{ get { return 1; } }
public string FixString { get; set; }
public BaseClass()
{
FixString = "hello";
}
public virtual int GetBaseVersion()
{
return Version;
}
}
public class DeriveClass: BaseClass
{
public new int Version
{ get { return 2; } }
}
猜猜看,这个方法会返回一个编译错误:
public void FreeConversion<T>(T baseClass)
{
if(baseClass.GetType()==typeof(DeriveClass)
var derivedMe = (DeriveClass)baseClass;
}
我必须先将baseClass
强制转换为object
才能将其投放到DerivedClass
,即
public void FreeConversion<T>(T baseClass)
{
if(baseClass.GetType()==typeof(DeriveClass)
var derivedMe = (DeriveClass)((object)baseClass);
}
对我来说很难看。为什么会这样?
答案 0 :(得分:7)
首先,您不应该将基类型变量强制转换为派生类型。它不应该起作用,只是相反。
其次,为什么它通过object
工作,是因为你删除了编译时类型检查。编译器可以检查BaseType
是否无法转换为DerivedType
。但是当变量为object
时,编译器会假设您知道自己在做什么。即使它会编译,代码也会在执行期间崩溃。
答案 1 :(得分:3)
答案很简单:编译器无法知道T
方法中的FreeConversion
可以转换为DeriveClass
。
答案 2 :(得分:1)
正如你已经说过的,便宜的伎俩是首先施放到物体,然后转移到你想去的类型。丑陋,但它确实有效。
除此之外,可能是你违反了Liskov Substitution原则,没有任何会伤害任何动物的东西,但可以将你的设计推向不可维护的代码。
第三,让你的基类公开派生类型的一个很好的技巧是这样的:
public class Base<T> where T : Base<T> {
T IAmDerived;
}
public class Derived : Base<Derived> { }
答案 3 :(得分:0)
首先,在您的通用方法中,类型T可以是值类型或引用类型。而它允许你通过'对象'做的原因是,你只是在做装箱拆箱,它适用于系统中的任何类型。
其次。将基类对象转换/转换为派生类将是一个可怕的想法。你违反了OOP的机制。
如果你真的想要返回一个派生自基类的类型的对象,这里有一种方法 - 解决方案与Frank提供的解决方案非常相似。
//This is how you create a function in BaseClass that returns the collection
//of DerivedTypes when called from an object of type derivedclass, no magic just Generics.
//**The BaseClass**
public class BaseClass<T>
where T : BaseClass<T>
{
public HashSet<T> GetHashSet()
{
HashSet<T> _hSet = new HashSet<T>();
//do some work
//create a HashSet<T> and return;
return _hSet;
}
}
//**The Derived Class**
public class DerivedClass : BaseClass<DerivedClass>
{
//you have the method inherited.
}