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.
}