如果BaseFruit有一个构造函数接受int权重,我可以实例化一个水果在一个泛型方法像这样?

public void AddFruit<T>()where T: BaseFruit{
    BaseFruit fruit = new T(weight); /*new Apple(150);*/
    fruit.Enlist(fruitManager);
}

注释后面添加了一个示例。似乎只有给BaseFruit一个无参数的构造函数,然后通过成员变量填充所有内容,才能做到这一点。在我的实际代码中(不是关于水果),这是相当不切实际的。

- update - 所以它似乎不能用任何约束条件来解决。从答案中可以得出三个备选方案:

工厂模式 反射 激活剂

我倾向于认为反射是最不干净的一种,但我无法在另外两种之间做出决定。


当前回答

另外还有一个简单的例子:

return (T)Activator.CreateInstance(typeof(T), new object[] { weight });

注意,在T上使用new()约束只是为了让编译器在编译时检查公共无参数构造函数,用于创建类型的实际代码是Activator类。

你需要确保自己了解特定的构造函数存在,这种需求可能是一种代码气味(或者更确切地说,在c#的当前版本中应该尽量避免的东西)。

其他回答

作为user1471935建议的补充:

要使用带有一个或多个参数的构造函数实例化泛型类,现在可以使用Activator类。

T instance = Activator.CreateInstance(typeof(T), new object[] {...}) 

对象列表是您想要提供的参数。微软表示:

调用CreateInstance(…]使用最匹配指定参数的构造函数创建指定类型的实例。

还有一个CreateInstance的通用版本(CreateInstance<T>()),但该版本也不允许提供构造函数参数。

这仍然是可能的,以高性能,通过做以下工作:

    //
    public List<R> GetAllItems<R>() where R : IBaseRO, new() {
        var list = new List<R>();
        using ( var wl = new ReaderLock<T>( this ) ) {
            foreach ( var bo in this.items ) {
                T t = bo.Value.Data as T;
                R r = new R();
                r.Initialize( t );
                list.Add( r );
            }
        }
        return list;
    }

and

    //
///<summary>Base class for read-only objects</summary>
public partial interface IBaseRO  {
    void Initialize( IDTO dto );
    void Initialize( object value );
}

然后,相关的类必须从该接口派生并相应地初始化。 请注意,在我的例子中,这段代码是周围类的一部分,该类已经有<T>作为泛型参数。 在我的例子中,R也是一个只读类。在我看来,Initialize()函数的公开可用性对不可变性没有负面影响。该类的用户可以放入另一个对象,但这不会修改底层集合。

是的,改变你的位置:

where T:BaseFruit, new()

但是,这只适用于无参数构造函数。您必须使用其他方法来设置属性(设置属性本身或类似的东西)。

你可以使用反射:

public void AddFruit<T>()where T: BaseFruit
{
  ConstructorInfo constructor = typeof(T).GetConstructor(new Type[] { typeof(int) });
  if (constructor == null)
  {
    throw new InvalidOperationException("Type " + typeof(T).Name + " does not contain an appropriate constructor");
  }
  BaseFruit fruit = constructor.Invoke(new object[] { (int)150 }) as BaseFruit;
  fruit.Enlist(fruitManager);
}

编辑:增加了构造函数== null检查。

编辑:一个更快的变种使用缓存:

public void AddFruit<T>()where T: BaseFruit
{
  var constructor = FruitCompany<T>.constructor;
  if (constructor == null)
  {
    throw new InvalidOperationException("Type " + typeof(T).Name + " does not contain an appropriate constructor");
  }
  var fruit = constructor.Invoke(new object[] { (int)150 }) as BaseFruit;
  fruit.Enlist(fruitManager);
}
private static class FruitCompany<T>
{
  public static readonly ConstructorInfo constructor = typeof(T).GetConstructor(new Type[] { typeof(int) });
}

最简单的解决方案 Activator.CreateInstance T < > ()