C# 继承泛型类时的多态性 让我们考虑有一个抽象基类和一个或多个子类: public abstract class BaseInnerClass { public int Id { get; set; } } public class ConcreteInnerClass : BaseInnerClass { public string Name { get; set; } }

C# 继承泛型类时的多态性 让我们考虑有一个抽象基类和一个或多个子类: public abstract class BaseInnerClass { public int Id { get; set; } } public class ConcreteInnerClass : BaseInnerClass { public string Name { get; set; } },c#,C#,然后,假设有一个泛型抽象类具有上述抽象类类型的属性: public abstract class GeneriAbstractTestClass<T> where T : BaseInnerClass { public T InnerClass { get; set; } } 这两个作业有什么区别?这与抽象类无关。一个更简单的例子是 List<BaseInnerClass> base = new List<ConcreteInnerClass>

然后,假设有一个泛型抽象类具有上述抽象类类型的属性:

public abstract class GeneriAbstractTestClass<T> where T : BaseInnerClass
{
    public T InnerClass { get; set; }    
}

这两个作业有什么区别?

这与抽象类无关。一个更简单的例子是

List<BaseInnerClass> base = new List<ConcreteInnerClass>
如果您想要的是可能的,那么以下方法将起作用:

GeneriAbstractTestClass<BaseInnerClass> genericClass = new ConcreteTestClass();
genericClass.InnerClass = new EvilConcreteInnerClass(); // OK, because the compiler sees `T` as `BaseInnerClass`
GeneriAbstractTestClass genericClass=new-ConcreteTestClass();
genericClass.InnerClass=新的InnerClass();//好的,因为编译器将'T'视为'BaseInnerClass'`

genericClass
变量指向其
T
泛型参数为
ConcreteInnerClass
的对象,因此将
指定给属性将导致运行时异常。

实际上。你可以这样做。但您需要使用协变out Tgeneric指定接口,因为进行这些强制转换是类型安全的

示例

namespace ConsoleTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var a = new Generic<Concrete>();
            IGeneric<Base> c = new Generic<Base>();
            c = a;
        }
    }

    public interface IGeneric<out T> where T: Base
    {
        T Inner { get; }
    }

    public class Generic<T> : IGeneric<T>
        where T : Base
    {
        public T Inner { get; set; }
    }

    public class Concrete : Base
    {
    }

    public class Base
    {
    }
}
名称空间控制台测试
{
班级计划
{
静态void Main(字符串[]参数)
{
var a=新的泛型();
IGeneric c=新的通用();
c=a;
}
}
公共接口IGeneric,其中T:Base
{
T内部{get;}
}
公共类泛型:IGeneric
其中T:Base
{
公共T内部{get;set;}
}
公共级混凝土:基础
{
}
公共阶级基础
{
}
}
如果委托指定了协变输出通用模板,则委托也不受限制

这意味着只要您使用只读泛型属性,您想要的强制转换就可以了。所以,正如@Kapol所说,并为您提供了一个示例,说明为什么允许属性上的setter或将T传递到函数中是不安全的

摘要


如果要使用这些类型的强制转换,请使用只读接口。

简单地说,
generabstracttestclass
不是
generabstracttestclass
,反之亦然,就像
列表一样-不确定这是否算是重复,但它非常接近。我认为阅读它会对你有所帮助:类不能是协变的,这就是问题所在。我同意,但这只是用C#设计的。没别的了。例如,C++中,可以使用协和来创建协变类,但这不是C++。我认为,更广泛地说,C++语法是有用的。
List<BaseInnerClass> base = new List<ConcreteInnerClass>
public class EvilConcreteInnerClass : BaseInnerClass
{
} 
GeneriAbstractTestClass<BaseInnerClass> genericClass = new ConcreteTestClass();
genericClass.InnerClass = new EvilConcreteInnerClass(); // OK, because the compiler sees `T` as `BaseInnerClass`
namespace ConsoleTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var a = new Generic<Concrete>();
            IGeneric<Base> c = new Generic<Base>();
            c = a;
        }
    }

    public interface IGeneric<out T> where T: Base
    {
        T Inner { get; }
    }

    public class Generic<T> : IGeneric<T>
        where T : Base
    {
        public T Inner { get; set; }
    }

    public class Concrete : Base
    {
    }

    public class Base
    {
    }
}