Bor*_*ens 212 .net c# generics
如果BaseFruit有一个接受一个的构造函数,int weight我可以用这样的泛型方法实例化一块水果吗?
public void AddFruit<T>()where T: BaseFruit{
BaseFruit fruit = new T(weight); /*new Apple(150);*/
fruit.Enlist(fruitManager);
}
Run Code Online (Sandbox Code Playgroud)
注释后面添加了一个示例.如果我给出BaseFruit一个无参数构造函数然后通过成员变量填充所有内容,我似乎只能这样做.在我的真实代码中(不是关于水果),这是不切实际的.
-Update-
所以它似乎无法以任何方式通过约束来解决.从答案中有三种候选解决方案:
我倾向于认为反射是最不干净的,但我不能在其他两个之间做出决定.
mea*_*ode 306
另外一个更简单的例子:
return (T)Activator.CreateInstance(typeof(T), new object[] { weight });
Run Code Online (Sandbox Code Playgroud)
请注意,在T上使用new()约束只是为了让编译器在编译时检查公共无参数构造函数,用于创建类型的实际代码是Activator类.
您需要确保自己关于现有的特定构造函数,并且这种要求可能是代码异味(或者更确切地说,您应该在c#的当前版本中尝试避免这种情况).
Jon*_*eet 90
您不能使用任何参数化构造函数.如果您有" where T : new()"约束,则可以使用无参数构造函数.
这是一种痛苦,但这就是生活:(
这是我想用"静态接口"解决的问题之一.然后,您可以将T约束为包含静态方法,运算符和构造函数,然后调用它们.
Ada*_*son 55
是; 改变你的位置:
where T:BaseFruit, new()
Run Code Online (Sandbox Code Playgroud)
但是,这仅适用于无参数构造函数.您必须有其他一些设置属性的方法(设置属性本身或类似的东西).
Jar*_*Par 17
正如Jon指出的那样,这是限制非参数构造函数的生命.然而,不同的解决方案是使用工厂模式.这很容易受到限制
interface IFruitFactory<T> where T : BaseFruit {
T Create(int weight);
}
public void AddFruit<T>( IFruitFactory<T> factory ) where T: BaseFruit {
BaseFruit fruit = factory.Create(weight); /*new Apple(150);*/
fruit.Enlist(fruitManager);
}
Run Code Online (Sandbox Code Playgroud)
另一种选择是使用功能方法.通过工厂方法.
public void AddFruit<T>(Func<int,T> factoryDel) where T : BaseFruit {
BaseFruit fruit = factoryDel(weight); /* new Apple(150); */
fruit.Enlist(fruitManager);
}
Run Code Online (Sandbox Code Playgroud)
mmm*_*mmm 11
你可以使用反射:
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);
}
Run Code Online (Sandbox Code Playgroud)
编辑:添加构造函数== 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) });
}
Run Code Online (Sandbox Code Playgroud)
作为 user1471935 建议的补充:
要使用带有一个或多个参数的构造函数实例化泛型类,您现在可以使用 Activator 类。
T instance = Activator.CreateInstance(typeof(T), new object[] {...})
Run Code Online (Sandbox Code Playgroud)
对象列表是您要提供的参数。根据微软的说法:
CreateInstance [...] 使用与指定参数最匹配的构造函数创建指定类型的实例。
还有一个通用版本的 CreateInstance ( CreateInstance<T>()) 但它也不允许您提供构造函数参数。