【发布时间】:2014-07-22 12:04:59
【问题描述】:
我知道,这里有一些关于 SO 的答案,似乎可以解决我的问题,例如 this 和 that 线程。但在我的具体情况下,有一些区别。
在我的问题前面:这是在带有参数的泛型中管理new() 约束的可能/智能解决方法吗?
假设以下基类:
abstract class BaseClass
{
internal BaseClass()
{
Console.WriteLine("{0}'s ctor (parameterless)", "BaseClass");
}
internal BaseClass(object parent)
{
Console.WriteLine("{0}'s ctor", "BaseClass");
Parent = parent;
}
public object Parent { get; private set; }
}
和界面:
interface IGenerate
{
IGenerate GenerateNew(int x, object parent);
}
基类只打算存储一个父对象,接口提供了一个方法来返回实现类调用其构造函数的对象,像这样:
class ClassX : BaseClass, IGenerate
{
public ClassX()
{
Console.WriteLine("{0}'s ctor (parameterless)", "ClassX");
}
public ClassX(int x, object parent)
: base(parent)
{
Console.WriteLine("{0}'s ctor", "ClassX");
X = x;
}
public IGenerate GenerateNew(int x, object parent)
{
Console.WriteLine("{0}.GenerateNew()", "ClassX");
return new ClassX(x, parent);
}
public int X { get; private set; }
}
我的泛型类旨在生成和存储调用接口方法的所提供类的对象:
class MyGeneric<T> : BaseClass where T : IGenerate, new()
{
public MyGeneric(int x, object parent)
: base(parent)
{
Console.WriteLine("{0}'s ctor", "MyGeneric");
Instance = new T().GenerateNew(x, this);
}
public IGenerate Instance { get; private set; }
}
另一个类继承了泛型:
class ClassXSpecifier : MyGeneric<ClassX>
{
public ClassXSpecifier(int x, object parent)
: base(x, parent)
{
Console.WriteLine("{0}'s ctor", "ClassXSpecifier");
}
}
这些结构的使用是这样的:
var classXspecifier = new ClassXSpecifier(5, null);
var classX = (ClassX)classXspecifier.Instance;
Console.WriteLine(classX.X);
输出:
BaseClass's ctor
MyGeneric's ctor
BaseClass's ctor (parameterless)
ClassX's ctor (parameterless)
ClassX.GenerateNew()
BaseClass's ctor
ClassX's ctor
ClassXSpecifier's ctor
5
再说一次我的主要问题:这是在带有参数的泛型中管理new() 约束的可能/智能解决方法吗?
第二个问题:为什么BaseClass 和ClassX 需要有一个无参数构造函数,而它们在任何情况下都不会被使用显式 ?如果我删除它们,我会收到以下错误:
'ClassX' 必须是具有公共无参数的非抽象类型 构造函数,以便将其用作泛型类型中的参数“T”或 方法'MyGeneric'
提前致谢,克里斯蒂安 =)
!!!解决方案!!!
提供的答案诱使我进行修改,即可以删除 new() 约束 -> 因此也可以删除无参数构造函数。
我删除了接口,在BaseClass中添加了一个静态方法来生成新对象:
public static BaseClass GenerateNew(Type T, object[] args)
{
return (BaseClass)Activator.CreateInstance(T, args);
}
所以泛型类可以简化为
class MyGeneric<T> : BaseClass
{
public MyGeneric(int x, object parent)
: base(parent)
{
Console.WriteLine("{0}'s ctor", "MyGeneric");
Instance = GenerateNew(typeof(T), new[] { x, parent });
}
public BaseClass Instance { get; private set; }
}
就是这样,也感谢所有 cmets!
【问题讨论】:
-
workaround to manage是什么意思? -
我过去通过使用另一个泛型参数
TFactory来解决这个问题,该参数受new()的约束,以及一个返回另一种类型T的接口,方法签名可以在其中使用参数。但是这种方法有些局限,我不记得我使用它的场景了。 -
关于第二个问题:因为这是签名要求的:
class MyGeneric<T> : BaseClass where T : IGenerate, new()-, new()表示“必须是具有公共无参数构造函数的非抽象类型" -
你不能做
new T(arg1, arg2,...)。那么你可以使用反射Activator.CreateInstance(选择相关的重载)。但有几点需要注意: 1. 反射可能会失败。 2. 反射发生在运行时,所以没有编译器优化。 -
@DanielA.White :我想知道,如果我以后在使用这些结构时会遇到问题,也许是文本中的一个不清楚的短语;)