Каков синтаксис для использования обобщений C # в качестве имени конструктора? - PullRequest
0 голосов
/ 11 июня 2009

У меня есть несколько классов, которые наследуются от Item<T>.

В каждом классе есть метод Create (), в который я хотел бы перейти в Item<T>.

Тем не менее следующий код получает ошибку " Невозможно создать экземпляр типа переменной 'T', поскольку у него нет ограничения new () ":

T item = new T(loadCode);

Что такое синтаксис для исправления , чтобы сделать это?

public abstract class Item<T> : ItemBase
{

    public static T Create(string loadCode)
    {
        T item = new T(loadCode);

        if (!item.IsEmpty())
        {
            return item;
        }
        else
        {
            throw new CannotInstantiateException();
        }
    }

Ответы [ 4 ]

9 голосов
/ 11 июня 2009

Это невозможно. Вы можете использовать только ограничение new() для принудительного существования конструктора.

Обходной путь - принять делегат Func<InputType, T> (Func<string,T> в вашем примере) в качестве входного параметра, который создаст объект для нас.

public static T Create(string loadCode, Func<string,T> construct)
{
    T item = construct(loadCode);

    if (!item.IsEmpty())
    {
        return item;
    }
    else
    {
        throw new CannotInstantiateException();
    }
}

и позвоните по номеру: Item<T>.Create("test", s => new T(s));

3 голосов
/ 11 июня 2009

Исправление : Я допустил небольшую ошибку, вам нужно еще одно ограничение на T для этого решения, см. Код ниже.

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

public interface ILoadable
{
    void Load(string loadCode);
}

public abstract class Item<T> : ItemBase
    where T : ILoadable, new()
{
    public static T Create(string loadCode)
    {
        T item = new T();
        item.Load(loadCode);

        if (!item.IsEmpty())
        {
            return item;
        }
        else
        {
            throw new CannotInstantiateException();
        }
    }
}

И затем вы реализуете код конструктора, который зависит от loadCode в переопределении до Load(...) в классах-потомках.

1 голос
/ 11 июня 2009

Ошибка в том, что компилятор не может полагаться на тот факт, что универсальный класс T имеет что-то кроме конструктора по умолчанию.

Вы можете преодолеть это с помощью отражения следующим образом:

ConstructorInfo c = typeof(T).GetConstructor(new Type[] { typeof(string) });
T t = (T)c.Invoke(new object[] { loadCode });

Поскольку ваш тип T, следовательно, должен иметь конструктор, который принимает строку, я бы также ограничил ваш класс, чтобы он наследовал от класса с конструктором:

class Item<T> : ItemBase where T : BaseClassWithConstructor
1 голос
/ 11 июня 2009

Вы можете использовать Activator.CreateInstance для создания экземпляра, хотя он не выполняет никаких проверок во время компиляции.

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