[英]Workaround for new() constraint with parameters in generics
我知道,这里有一些关于 SO 的答案,它们似乎解决了我的问题,比如这个和那个线程。 但在我的具体情况下,有一些区别。
在前面我的问题:这是一种可能/智能的解决方法来管理带有参数的泛型中的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”必须是具有公共无参数构造函数的非抽象类型,以便将其用作泛型类型或方法“MyGeneric”中的参数“T”
提前致谢,克里斯蒂安 =)
!!! 解决方案 !!!
提供的答案诱使我进行修改,即可以删除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; }
}
就是这样,也感谢所有评论!
题
再次我的主要问题:这是一种可能/智能的解决方法来管理带有参数的泛型中的 new() 约束吗?
回答
您传递了一个类型(ClassX)并希望在不创建实例的情况下访问一个实例函数(GenerateNew)-> 好吧,这是您需要考虑的一个问题。 您可以创建一个静态工厂(和/或使用 IOC)来按类型创建新对象。
题
为什么 BaseClass 和 ClassX 需要有一个无参数构造函数,而它们在任何情况下都不会显式使用?
回答
此约束要求使用的泛型类型是非抽象的,并且它具有允许您调用它的默认(无参数)构造函数。 顺便说一句,您正在通过执行new T()
来使用空 ctor。
不是最好的解决方案,但我曾经做过的是需要一个返回泛型类型并提供构造函数作为函数参数的函数:
void GenericMethod<T>(Func<string, T> ctor)
{
T t = ctor("foo");
}
要调用该方法,请使用名为 Foo 的类作为泛型类型: GenericMethod((arg) => new Foo(arg))
args 不需要在调用泛型方法之前定义,仅用于指示如何使用 ctor 的参数。它还使方法更加灵活,因为调用者可以选择使用方法而不是构造函数,像 System.Drawing.Image.FromFile() 或使用返回它的 lambda 表达式的现有对象。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.