C# 为什么泛型约束可以';不能转换为其派生类型吗?
发现泛型约束不能强制转换为其派生类型是相当令人费解的 假设我有以下代码:C# 为什么泛型约束可以';不能转换为其派生类型吗?,c#,generics,C#,Generics,发现泛型约束不能强制转换为其派生类型是相当令人费解的 假设我有以下代码: public abstract class BaseClass { public int Version { get { return 1; } } public string FixString { get; set; } public BaseClass() { FixString = "hello"; } public virtual in
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;
}
在我看来很难看。为什么会这样?首先,您不应该将基类型变量强制转换为派生类型。它不应该起作用,相反的
其次,它通过
对象工作的原因是您删除了编译时类型检查。编译器可以检查BaseType
是否不能转换为DerivedType
。但是当一个变量是对象时,编译器会假定您知道自己在做什么。即使它将编译,代码也会在执行过程中崩溃。答案很简单:编译器无法知道FreeConversion
方法中的t
可以转换为DeriveClass
正如您已经说过的,便宜的技巧是先将其转换为object,然后再转换为您想要转换的类型。很难看,但很管用
除此之外,您可能违反了Liskov替换原则,没有任何东西会伤害任何动物,但会将您的设计推向无法维护的代码
第三,让基类公开派生类型的好方法如下:
public class Base<T> where T : Base<T> {
T IAmDerived;
}
public class Derived : Base<Derived> { }
公共类基,其中T:Base{
T推导;
}
派生的公共类:基类{}
首先,在通用方法中,类型T可以是vale类型或引用类型。它允许您通过“对象”进行操作的原因是,您只需进行装箱拆箱,这适用于系统中的任何类型
其次,将基类对象转换/强制转换为派生类将是一个糟糕的想法。你违反了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.
}
//这就是如何在基类中创建返回集合的函数的方法
//当从derivedclass类型的对象调用DerivedTypes时,没有魔力,只有泛型。
//**基类**
公共类基类
其中T:BaseClass
{
公共HashSet GetHashSet()
{
HashSet hSet=新HashSet();
//做些工作
//创建一个HashSet并返回;
返回(hSet),;
}
}
//**派生类**
公共类派生类:基类
{
//您继承了该方法。
}
为什么编译器不知道?我认为它应该知道,因为我明确指定DeriveClass
是BaseClass
@Ngu的继承类:不,您没有。测试以查看T
是否属于DeriveClass
类型,然后,独立于测试,尝试显式地将T
强制转换为DeriveClass
。记住,编译器不会运行您的代码,它只是编译。您可以使用as
子句而不是显式转换来进行转换baseClass as DeriveClass
将尽可能以DeriveClass
的形式返回实例,否则将返回null
——但如果您先检查它是否可能(正如您现在所做的),您就知道(即使您的代码不知道),它将永远不会是null
@Ngu,因为没有人知道,所以编译器无法知道!当模板被创建时,没有什么可以说它将只接收一个基类参数,当然也没有什么可以说它将是一个DerivedClass值。例如,没有什么可以阻止某人调用FreeConversion(42)
。唯一的例外是模板的成员方法被限制为从其自身的参数派生(在某些情况下实际上很有用)。
//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.
}