C# 是否可能对继承层次结构中类的泛型成员施加类型约束?

C# 是否可能对继承层次结构中类的泛型成员施加类型约束?,c#,generics,inheritance,polymorphism,C#,Generics,Inheritance,Polymorphism,我正在用C#编写一个应用程序,正在努力实现它的泛型。我有一个继承层次结构,它由另一个继承层次结构(模型和视图模型)镜像,如下所示: 这很好,但意味着当我只有一个as的集合时,我无法访问content的公共元素。我真正想做的是: abstract class A_Content { } class B_Content : A_Content { public string Bar; } class C_Content : A_Content { public string Fo

我正在用C#编写一个应用程序,正在努力实现它的泛型。我有一个继承层次结构,它由另一个继承层次结构(模型和视图模型)镜像,如下所示:

这很好,但意味着当我只有一个
a
s的集合时,我无法访问
content
的公共元素。我真正想做的是:

abstract class A_Content { }

class B_Content : A_Content
{
    public string Bar;
}

class C_Content : A_Content
{
    public string Foo;
}

abstract class A<T> { T content; }
class B : A<B_Content> { }
class C : A<C_Content> { }

public class Test {
    IList<A<A_Content>> A_Collection = new List<A<A_Content>>();

    public Test()
    {
        B b = new B();
        C c = new C();

        A_Collection.Add(b);
        A_Collection.Add(c);
    }
}
抽象类A_内容{}
B类内容:A类内容
{
公共字符串栏;
}
C类内容:A类内容
{
公共字符串Foo;
}
抽象类A{T内容;}
B类:A{}
C类:A{}
公开课考试{
IList A_Collection=新列表();
公开考试()
{
B=新的B();
C=新的C();
A_集合。添加(b);
A_集合。添加(c);
}
}

但是,这会产生一个错误,抱怨B不能隐式转换为A。我尝试添加显式强制转换,但没有效果。有没有什么方法可以比第二个模型更优雅地表达我所寻找的约束条件?

还不完全清楚你想要什么。您是否试图使
A
的每个实例都有一个
Content
属性,其类型为
A\u Content
,每个
B
都有一个
Content
属性,即A
B\u Content
,依此类推?如果是这样,您就不能这样做,而让
B
/
C
/等继承自
A
。(无论如何,不是以一种没有臭味的方式)。
A
的签名表示
Content
属性应该能够获取(并且可能设置)
A\u Content
的任何有效值。不能更改函数的返回类型或派生类中属性或字段的类型。您可以使用泛型基本上将属性的类型化一直推迟到类的使用,但是这种语法会很难看,我不确定它会给您带来什么

例如,您可以这样做:

public class A<TContent> where TContent : A_Content
{
    public TContent Content { get; set; }
} 

public class B<TContent> : A<TContent> where TContent : B_Content
{
   // nothing here, as the property is already defined above in A
}

public class C<TContent> : A<TContent> where TContent : C_Content
{
   // nothing here, as the property is already defined above in A
}

这显然会中断,因为
foo
实际上是一个
B
,所以运行时不允许您将
内容
设置为除
B_内容
(或从其继承的内容)
的实例以外的任何内容,但是类的签名意味着您应该能够分配属于
A_Content`或从中继承的任何内容。

您可以为此使用接口,以及接口成员的显式实现:


现在,
B
仍然无法转换为
A
,但它可以转换为
IA
,因此您可以使用
列表来保存对象的同质集合。

好吧,编译器会产生一个错误,因为
B
确实无法转换为
A
。 这是因为
A
不是
B
的超类。
B
类的父类是
A

恐怕你需要坚持选角。这里需要它,因为您有
A
s的列表。 如果你真的想避免铸造(我不知道为什么你想),你可以尝试与动态调度

您可以尝试创建一个
列表
,而不是
列表

不过,您至少需要C#4.0。

希望我能理解您的意图,所以

有这样的收藏

IList
意味着您希望拥有具有不同实现场景的
a
对象的集合

如果该属性是基类型的属性,则为该属性。这意味着基类型必须公开方法/属性=>so状态和行为原语,子类必须对此原语进行具体实现

大概是这样的:

class A_Content {  public virtual string Bar {get;set;} }

class B_Content : A_Content
{
    public override string Bar {get;set;};
}

class C_Content : A_Content
{
    public override string Bar {get;set};
}
在代码的某个地方:

public Test()
{
      B b = new B();
      C c = new C();

      A_Collection.Add(b);
      A_Collection.Add(c);

      //so
      A_Collection[0].Bar // B::Bar 
      A_Collection[1].Bar //C::Bar 

}

您不需要将其转换为真实对象。简单的面向对象方法。

如果我正确理解了这个问题,那么您在这里寻找的是一个接口。你想要一个每个集合都可以访问的列表(),不是吗?@BillCarey:你不应该这样做,因为通过强制转换到特定类型,你会失去OOP的潜力。查看我的答案,了解另一个想法。
List<A<A_Content>> list = new List<A<A_Content>>();

list.Add(new B()); // this seems OK so far, right? 

A<A_Content> foo = list[0];

foo.content = new A_Content():
abstract class A_Content {}
class B_Content : A_Content {}
class C_Content : A_Content {}

interface IA
{
    A_Content content { get; }
}

abstract class A<T> : IA
    where T : A_Content
{
    T content;
    A_Content.content { get { return this.content; } }
}

class B : A<B_Content> {}
class C : A<C_Content> {}
interface IA<out T>
{
    T content { get; }
}

abstract class A<T> : IA<T>
    where T : A_Content
{
    T content { get; set; }
}

class B : A<B_Content> {}
class C : A<C_Content> {}
class A_Content {  public virtual string Bar {get;set;} }

class B_Content : A_Content
{
    public override string Bar {get;set;};
}

class C_Content : A_Content
{
    public override string Bar {get;set};
}
public Test()
{
      B b = new B();
      C c = new C();

      A_Collection.Add(b);
      A_Collection.Add(c);

      //so
      A_Collection[0].Bar // B::Bar 
      A_Collection[1].Bar //C::Bar 

}