Как добавить общее ограничение в конструктор неуниверсального класса в C # - PullRequest
3 голосов
/ 29 октября 2011

Как видно из заголовка, я хотел бы сделать следующее, но компилятор не разрешит мне:

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 и, следовательно, нет поддержки ковариантных обобщений.

Ответы [ 3 ]

6 голосов
/ 29 октября 2011

Конструкторы в 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();
6 голосов
/ 29 октября 2011

Вы можете использовать фабричный шаблон для решения вашей проблемы:

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> и быть счастливым)

0 голосов
/ 29 октября 2011

Вы не можете сделать это в 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());
}

В-четвертых, вы можете создать универсальный класс, производный от вашего базового класса, как кто-то уже указал.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...