【问题标题】:c# generics with abstract methodc#泛型与抽象方法
【发布时间】:2019-10-10 22:45:24
【问题描述】:

我正在尝试为抽象类实现一些通用方法,如下所示:

public abstract class MyAbstractClass : MyBaseObject {
    public MyAbstractClass() : base() { } // there is a parameterless constructor...
}

public class MyList<T> where T : MyBaseObject, new() {
    // a generic container that is designed for the base class
}

//--- some paint control of mine
public class PaintControl : IDisposable {
    public void InitDrawItems(MyList<MyAbstractClass> items) {
        // paint items => this is where the compilation error occurs...
    } 
}

我得到以下编译错误:

错误 24“MyAbstractClass”必须是具有公共无参数构造函数的非抽象类型,才能将其用作泛型类型或方法“MyList”中的参数“T”

当然,我想使用抽象的 MyAbstractClass 类(它有几个孩子来相应地处理绘画)。 有没有办法解决这个问题?

编辑:我确实创建了抽象类,以确保孩子们确实实现了抽象方法。

【问题讨论】:

  • 你不能新建一个抽象类
  • 来自官方文档:新约束指定泛型类声明中的任何类型参数都必须具有公共无参数构造函数。 要使用新的约束,类型不能是抽象的。见:docs.microsoft.com/en-us/dotnet/csharp/language-reference/…
  • 好的,有 2 条出路 1. 将 MyAbstractClass 设为非抽象或在 PainControl 中使用特定的非抽象子,对吗?
  • @neggenbe 接口不能解决问题,你也不能创建接口实例。
  • 您还可以删除Tnew() 约束。这实际上意味着您不能将抽象类或接口与MyList 一起使用。

标签: c# generics


【解决方案1】:

new() 不允许抽象类和接口用作T,因为它们不可实例化。 new() 表示泛型类型必须声明一个公共无参数构造函数,该构造函数有资格实例化对象。 所以你有一个选择,在我看来: 删除new() 子句,如果您可以接受从MyBaseObject 派生的任何抽象类型与您的泛型一起使用。由于您的课程确实是抽象的,并且是MyBaseObject 的孩子,因此可以正常工作。

【讨论】:

    【解决方案2】:

    这是由generic type variance 引起的问题。声明一个具体类型实际上是在编译时创建一个新类型。类中的 type 参数不能在类型之间进行隐式转换。 MyList&lt;MyBaseObject&gt;MyList&lt;MyConcreteObject&gt; 之间没有继承关系。

    只允许对通用接口或委托进行转换。

    有两种方法可以解决这个问题 - 使用接口而不是具体类,例如:

    class MyList<T>:IList<T> where T : MyBaseObject, new() 
    {
    
    }
    
    class PaintControl  {
        public void InitDrawItems<T>(IList<MyAbstractClass> items) //where T:MyAbstractClass,new()
        {
            //var anItem=new T();
        } 
    }
    

    或将InitDrawItems 本身设为通用:

    public void InitDrawItems<T>(MyList<T> items) where T:MyAbstractClass,new()
    {
        // No compilation errors here
    } 
    

    【讨论】:

      【解决方案3】:

      您应该删除 TMyList 类型的 new() 约束,因为它指定您只能使用可以初始化的类型 - 抽象类型不能。

      您可以在此处查看更多详细信息:https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/where-generic-type-constraint

      【讨论】:

        【解决方案4】:

        答案似乎有点解决方法,但实际上很有意义......

        我确定我正在处理列表中的哪个项目(我正在遍历项目)。由于这个项目已经创建,它肯定是一个非抽象类。因此,我可以调用该项目的激活器,而不是 new T()

        public void InitDrawItems(MyList<MyAbstractClass> items)
          foreach (var item in items) {
            Type type = o.GetType();
            // type is definitely NOT abstract, since the object was created, so it is a
            // non-abstract child class and I create the right "copy" of the item !
            MyAbstractClass newItem = Activator.CreateInstance(type) as MyAbstractClass;
            // ... do whatever I need with the item
          }
        }
        

        注意:对于泛型,抽象类不允许调用 new T() 是有道理的。这么说吧:通用抽象项的容器包含派生子类的项,因为无法实例化抽象父类。因此,如果编译器允许,调用new T() 肯定会导致问题:应该是哪个子类?!?

        【讨论】:

          【解决方案5】:

          正如@Martin 在 cmets 中指出的那样,来自docs

          新约束指定泛型类声明中的任何类型参数都必须具有公共无参数构造函数。 要使用新的约束,类型不能是抽象的。

          还有你编写的定义MyList&lt;T&gt;的代码:

          public class MyList<T> where T : MyBaseObject, new()
          

          MyList&lt;T&gt; 是一个泛型类,其中 T 必须具有新的约束(是可以实例化的类型)。

          所以你的代码编译错误的原因:

          public void InitDrawItems(MyList<MyAbstractClass> items)
          

          因为在这种情况下TMyAbstractClass,这是一个无法实例化的抽象类。

          所以你的选择如下:

          1. 使方法通用,如下所示:

            public void InitDrawItems<T>(MyList<T> items) where T : MyAbstractClass, new()
            {
                // paint items => this is where the compilation error occurs...
            }
            
          2. T 中删除MyList 中的新约束

          3. 使MyAbstractClass 成为普通类而不是抽象类。

          【讨论】:

            【解决方案6】:

            这很简单,你不能实例化一个抽象类,所以T = MyAbstractClasswhere T : new() 约束冲突。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2018-07-05
              • 1970-01-01
              • 1970-01-01
              • 2012-03-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多