继承一个泛型基类,应用一个约束,并在 C # 中实现一个接口

这是句法问题。我有一个泛型类,它继承自一个泛型基类,并将一个约束应用于一个类型参数。我还希望派生类实现一个接口。我怎么也想不出正确的语法。

这就是我所拥有的:

DerivedFoo<T1,T2> : ParentFoo<T1, T2> where T2 : IBar { ... }

我想到的第一件事是:

DerivedFoo<T1,T2> : ParentFoo<T1, T2> where T2 : IBar, IFoo { ... }

但这是不正确的,因为这导致 T2需要同时实现 IBar 和 IFoo,而不是派生 Foo 来实现 IFoo。

我尝试过用谷歌搜索,使用冒号、分号等等,但结果都不行。答案肯定很简单。

90346 次浏览

在定义泛型约束之前,需要包含类的整个签名。

class DerivedFoo<T1, T2> : ParentFoo<T1, T2>, IFoo where T2 : IBar
{
...
}
public interface IFoo {}
public interface IBar {}


public class ParentFoo<T,T1> { }
public class DerivedFoo<T, T1> : ParentFoo<T, T1>, IFoo where T1 : IBar { }

我的建议是: 当您对 C # 语言的语法有疑问时,请阅读规范; 这就是我们发布它的原因。你应该读读10.1节。

为了回答您的具体问题,类声明中的顺序是:

  • 属性,放在方括号中
  • 修饰符(“ public”、“ static”等)
  • “部分”
  • “班级”
  • 类名
  • 在尖括号内用逗号分隔的类型参数声明列表
  • 冒号后面是逗号分隔的基类型列表(基类和已实现的接口,如果有基类,则必须首先显示)
  • 类型参数约束类型参数约束
  • 班级的主体,被括号包围着
  • 分号

除了“ class”、名称和主体之外,列表中的所有内容都是可选的,但是如果出现,则所有内容都必须按照这个顺序出现。

public class KeyAndValue<T>
{
public string Key { get; set; }
public virtual T Value { get; set; }
}


public class KeyAndValue : KeyAndValue<string>
{
public override string Value { get; set; }
}

这是现有答案的扩展。如果不提供类型,则默认为 string。我没有实现一个接口,但是它不应该需要任何与通常不同的东西。

通用继承规则

在继承 C # 中的泛型类型类时,还需要遵循额外的 规矩。请记住,基类和派生类可以使用不同的泛型类型或共享它们。下面的测试帮助我理解了这些规则。泛型类可以从具体的、封闭构造的或开放构造的基类继承,如下所示:

// First create some Base Classes to inherit from.
// Non-generic and generic classes are included.
// Below, I will inherit these in Derived Classes.
// If my inheritance test works, you will see "YES", otherwise "NO".


class BaseType1 { }
class BaseType2<T> { }
class BaseType3<T1,T2> { }


// -------------------------------------------------


// Concrete type inheritance. Here the inheriting type does NOT have to be generic as the child


class Derived1 : BaseType1 { }// YES!
class Derived2<T> : BaseType1 { }// YES!


// Open constructed type generic inheritance allows shared generic type inheritance.
class Derived3<T> : BaseType2<T> { }// YES!


// Closed constructed type inheritance. Note that what the child class accepts as far as types is different from what the parent accepts. This is allowed allowed as each implements its own types and constraints on its members and the parent has defined its type.
class Derived4<T> : BaseType2<int> { }// YES!


// NO! Base type must know its accepted type if the child class is not accepting a generic "T" type as well.
//class Derived5 : BaseType2<T> { }// NO!


// Another form that limits generic type. Note, here the first base type uses a reference type "string" that is different from what the derived child type uses, which is any "struct" type or int, etc. Because the base type is defined as "string" the child can define anything for its generic or not even use a generic.


// The "where" clause only affects the derived class type!
class Derived6<T> : BaseType2<T> where T : struct { }// YES!
class Derived7<T> : BaseType2<string> where T : struct { }// YES!


// NO! The "where" clause cannot be used to define the base class's type!
//class Derived8 : BaseType2<T> where T : struct { }// NO!




// NO! "T1" and "T2"must be a concrete type again if the derived type doesn't use the same
//class Derived9 : BaseType3<T1,T2>// NO!


// Here, both parent and child classes must accept one generic type for this to work.
class Derived10<T> : BaseType3<T,T> { }// YES!


// Each generic type must have unique names in the derived class AND match the base class names. That is why these fail.
//class Derived11<T, T> : BaseType3<T1, T2> { }// NO!
//class Derived12<name1, name2> : BaseType3<T1, T2> { }// NO!


class Derived13<T1, T2> : BaseType3<T1, T2> { }// YES!


// As long as one generic name matches between child and parent, this shared generic type on child and parent ok.
class Derived14<Tname,T2> : BaseType2<Tname> { }// YES!


// Again, the child class doesn't have to be generic if the base generic class has defined the types it accepts.
class Derived15 : BaseType3<string, int> { }// YES!


class Derived16<T1, T2> : BaseType3<string, int> { }// YES!


// Here, you can have the child class accept two generic types, while the parent uses its own explicit type.
class Derived17<T1, T2> : BaseType2<string> { }// YES!


// No, you need to define these using "where".
//class Derived18<string, int> : BaseType1 { }// NO!


class Derived19<T1, T2> : BaseType1 where T1 : class where T2 : struct { }// YES!


// This generates an error. You cannot inherit a generic type.
// class Derived20 : T {}// NO!