繁体   English   中英

如何在C#中向非泛型类的构造函数添加泛型约束

[英]How to add a generic constraint to a constructor of a non-generic class in C#

正如标题所示,我想做以下,但编译器不会让我:

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。

任何人都可以帮我解决这个问题吗? 这有可能吗? 它肯定是在Java :)

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

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

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<SomeSuperType>并且很开心)

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();

你不能在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());
}

第四种解决方案,你可以创建一个派生自你的基类的泛型类,就像有人已经指出的那样。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM