使用C#泛型作为构造函数名称的语法是什么?

时间:2009-06-11 11:40:55

标签: c# generics inheritance

我有许多继承自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 个答案:

答案 0 :(得分:9)

这是不可能的。您只能使用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));

进行调用

答案 1 :(得分:3)

更正:我犯了一个小错误,此解决方案需要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(...)

答案 2 :(得分:1)

您可以使用Activator.CreateInstance创建实例,但它不会进行任何编译时检查。

答案 3 :(得分:1)

错误是因为编译器不能依赖泛型类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