Создание экземпляра универсального типа в C #

2

У меня есть специализированный универсальный класс коллекций, который будет использоваться для хранения коллекций различных типов объектов. Как только коллекция создана, мне нужно создать ее элементы. У меня самое страшное время заставить это работать. Там должно быть простое решение, которое я пропускаю.

Вот пример класса, который как бы иллюстрирует то, что я пытаюсь сделать, и предупреждения/ошибки, с которыми я сталкиваюсь.

// Note: T may either a string or other reference type that supports IEnumerable. 
public class Foo<T>
{
    private List<T> fooBarList = new List<T>();

    public Foo()
    {
        Bar1<T>();
        Bar2<T>();
        Bar3<T>();
    }

    public void Bar1<T>()
    {
        // Error Message: Argument 1 cannot convert from 'T...' to 'T...'
        T t = default;
        fooBarList.Add(t);
    }

    public void Bar2<T>() where T : IEnumerable, new()
    {
        // Error Message: T must be a non-abstract type with public
        // parameterless constructor in order to use it as a parameter 'T'
        // in the generic type or method 'Foo<T>.Bar2<T>()

        fooBarList.Add(new T());
    }

    public void Bar3<T>() where T : IEnumerable, new()
    {
        // Error Message: Argument 1 cannot convert from 'T...' to 'T...'
        T t = Activator.CreateInstance<T>();
        fooBarList.Add(t);
    }
}

Примечание: этот конкретный код находится в критически важной части моего приложения - вы знаете, что 3% Дональд Кнут говорит о необходимости оптимизации. Это действительно должно быть быстрым, потому что оно будет вызываться миллионы раз за выполнение приложения. Я не был бы в восторге от использования отражения (например, Activator.CreateInstance() здесь), если есть какая-либо другая альтернатива. (На данный момент даже это, похоже, не работает для меня.) Я бы предпочел, чтобы компилятор разрешил тип данных во время компиляции.

На этот вопрос уже ответили по ссылке ниже, но ни один из подходов, похоже, не работает для меня. Что мне не хватает?

В С# как создать экземпляр переданного универсального типа внутри метода?

К вашему сведению, я использую .NET Core 2.2 Beta и .NET Standard 2.0 на компьютере с Windows 10 под управлением Visual Studio 2019 Enterprise Preview.

  • 2
    public void Bar1<T>() ... должен быть public void Bar1() , эти методы не должны быть универсальными, а скорее использовать универсальный тип класса
  • 0
    Я думаю, что @vc74 vc74 имеет правильное решение или близко к нему. Вам нужно объявить предложение where для T (указав, что T является коллекцией и является новым) на уровне класса, а затем удалить биты <T> на уровне функции.
Показать ещё 7 комментариев
Теги:
generics

2 ответа

2

Кажется, что List<T> уже имеет все необходимое, кроме метода для создания нового экземпляра и добавления его, который может быть добавлен как метод расширения:

public static ICollectionExtensions
{
    public static AddNew<T>(this ICollection<T> collection)
        where T : new()
    {
        var newItem = new T();
        collection.Add(newItem);
    }

    ...
} 

который можно использовать так:

var list = new List<int>();
list.AddNew();
1

Это компилирует:

public class Foo<T> where T : IEnumerable, new()
{
    private List<T> fooBarList = new List<T>();

    public Foo()
    {
        Bar1();
        Bar2();
        Bar3();
    }

    public void Bar1()
    {
        T t = default(T);
        fooBarList.Add(t);
    }

    public void Bar2()
    {
        fooBarList.Add(new T());
    }

    public void Bar3() 
    {
        T t = Activator.CreateInstance<T>();
        fooBarList.Add(t);
    }
}

Обратите внимание, что единственное объявление T находится на уровне класса, как часть <T> часть where.

  • 1
    Уверен, что это не сработает, если у конкретного типа T нет открытого конструктора без параметров.
  • 4
    @RobertHarvey Вот что означает ограничение new() ...
Показать ещё 6 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню