【问题标题】:What is the syntax to use C# generics as a constructor name?使用 C# 泛型作为构造函数名称的语法是什么?
【发布时间】:2010-11-02 02:40:16
【问题描述】:

我有许多继承自 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();
        }
    }

【问题讨论】:

    标签: c# generics inheritance


    【解决方案1】:

    这是不可能的。您只能使用new() 约束来强制存在构造函数。

    一种解决方法是将Func&lt;InputType, T&gt;(在您的示例中为Func&lt;string,T&gt;)委托作为输入参数,为我们创建对象。

    public static T Create(string loadCode, Func<string,T> construct)
    {
        T item = construct(loadCode);
    
        if (!item.IsEmpty())
        {
            return item;
        }
        else
        {
            throw new CannotInstantiateException();
        }
    }
    

    并通过以下方式调用它:Item&lt;T&gt;.Create("test", s =&gt; new T(s));

    【讨论】:

    • 不是 OP 只是在问他如何才能正确编译出那段代码吗?
    • @activa:根本没有办法直接让它工作。这个想法在 C# 中根本不受支持。
    【解决方案2】:

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

    【讨论】:

    • 第一个想法行不通。派生类可以有一组单独的构造函数。 Activator.CreateInstance 可以工作,但它不会在编译时强制执行任何操作,因此代码可能会完美编译并在运行时出人意料地失败,这不是一件好事。
    • 对。它必须调用 base(ItemBase),但派生类本身不必具有那个特定的 ctor。我的错,会改变的。
    【解决方案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();
            }
        }
    }
    

    然后您实现构造函数代码,该代码依赖于后代类中 Load(...) 的覆盖中的 loadCode

    【讨论】:

    • 但是编译器无法知道 T 上存在 Load()。你需要一个额外的约束(例如一个接口)
    • 你是对的......我被问题的措辞分心,以为 T 是 Item 类型...... duh。
    • 不幸的是,如果 T 将用作框架提供的类,例如,这种方法不起作用。 Exception的子类,只能在构造函数中赋值属性(即它们的Message)...
    【解决方案4】:

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

    【讨论】:

    • 正如我在另一条评论中所说,这可行但不安全。而且您的限制对派生类没有任何意义。基类将有一个无参数构造函数,而派生类可能没有。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-07
    • 1970-01-01
    相关资源
    最近更新 更多