【问题标题】:How to add a generic constraint to a constructor of a non-generic class in C#如何在 C# 中向非泛型类的构造函数添加泛型约束
【发布时间】:2011-12-17 18:38:42
【问题描述】:

正如标题所示,我想做以下事情,但编译器不让我这样做:

public class MyClass
{
    private List<SomeSupertype> myList;

    public MyClass<T> (ICollection<T> elements) where T : SomeSupertype
    {
        myList = new List<SomeSuperType> ();
        foreach (SomeSupertype element in elements) {
            myList.Add (element);
        }
    }
}

不知何故,似乎不可能将泛型参数添加到本身不是泛型的类的构造函数中。请注意,MyClass 应该是非泛型类型,因为一旦构建了 MyClass,客户端就不必区分不同类型的 MyClass。

谁能帮我解决这个问题?这可能吗?它肯定是在 Java 中的 :)

编辑:我忘了提到我使用的是 .NET 3.5,因此不支持协变泛型。

【问题讨论】:

  • 如果您使用的是 .NET 4,为什么不让非泛型构造函数采用 IEnumerable&lt;SomeSupertype&gt;IEnumerable1` 是协变的,所以 IEnumerable&lt;T&gt; 可以转换为 IEnumerable&lt;SomeSupertype&gt; 每当 T : SomeSupertype 时。
  • @Anton:经过一些改写和解释,这似乎值得回答
  • 是的,协方差可以解决问题。我可能应该提到我正在使用 .NET 3.5

标签: c# .net oop generics


【解决方案1】:

您不能在 C# 中执行此操作。这是一件好事,因为我们不希望构造函数与类不匹配。但是仍然有几种方法可以实现您的目标。

最简单的方法(如果您使用 C# 4)是使用 IEnumerable 而不是 ICollection,因为 IEnumerable 支持逆变。

public class MyClass
{
    private List<SomeSupertype> myList;

    public MyClass (IEnumerable<SomeSuperType> elements)
    {
        myList = new List<SomeSuperType> ();
        foreach (SomeSupertype element in elements) {
            myList.Add (element);
        }
    }
}

现在您可以调用构造函数,而无需考虑将派生类型的集合转换为基类型的集合。

List<SomeDerivedClass> col = new List<SomeDerivedType>();
MyClass obj1 = new MyClass(col)

第二种解决方案,您可以通过使用 LINQ 强制转换集合来调用您的构造函数。

MyClass obj1 = new MyClass(col.Cast<SomeSuperClass>());

第三种解决方案,您可以创建静态泛型方法来构造类的新对象。

public static MyClass Construct<T>(ICollection<T> elements) where T : ClassA
{
    return new MyClass(elements.Cast<ClassA>().ToArray());
}

第四个解决方案,您可以创建一个从您的基类派生的泛型类,正如有人已经指出的那样。

【讨论】:

    【解决方案2】:

    C# 中的构造函数不能是通用的(同上事件、属性、析构函数、运算符)。考虑创建一个静态通用工厂方法:

    public class MyClass
    {
        private List<SomeSupertype> myList;
    
        private MyClass(List<SomeSupertype> myList)
        {
            this.myList = myList;
        }
    
        public static MyClass Create<T>(ICollection<T> elements)
            where T : SomeSupertype
        {
            var myList = new List<SomeSuperType>(elements);
            foreach (SomeSupertype element in elements)
            {
                myList.Add(element);
            }
            return new MyClass(myList);
        }
    }
    

    顺便说一下,即使在 .NET 3.5 中,您也可以使用 LINQ 来简化列表创建:

    var myList = elements.Cast<SomeSuperType>().ToList();
    

    【讨论】:

      【解决方案3】:

      您可以使用工厂模式来解决您的问题:

      public class MyClass
      {
          private List<SomeSuperType> myList = new List<SomeSuperType>();
      
          public static MyClass MyClassBuilder<T>(ICollection<T> elements) where T : SomeSuperType
          {
              var myClass = new MyClass();
      
              foreach (SomeSuperType element in elements)
              {
                  myClass.myList.Add(element);
              }
      
              return myClass;
          }
      
          protected MyClass()
          {
          }
      }
      

      或者您可以创建两个类,如下所示:

      // Put all the methods here
      public class MyClass
      {
          protected List<SomeSuperType> myList = new List<SomeSuperType>();
      
          protected MyClass()
          {
          }
      }
      
      // This class will define only the generic constructor
      public class MyClass<T> : MyClass where T : SomeSuperType
      {
          public MyClass(ICollection<T> elements)
          {
              foreach (SomeSuperType element in elements)
              {
                  myList.Add(element);
              }
          }
      }
      

      (这忽略了这样一个事实,正如 Anton 所写,在 C# >= 4.0 中,您可以简单地接受 IEnumerable&lt;SomeSuperType&gt; 并感到高兴)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多