问题描述
泛型类型中众所周知的约束是 new(),可以添加像 (args,args,...) 这样的参数来强制编译器检查该类是否包含特定的构造函数?
该块向您展示了案例。
public class FooType
{
public FooType(int arg1)
{
}
}
public sealed class FooTypeChildA : FooType
{
public FooTypeChildA(int a) : base(a)
{
}
}
public sealed class FooTypeChildB : FooType
{
public FooTypeChildB() : base(0)
{
}
}
//public class FooConstraint<T> where T : FooType,new() // SUCCESS
//public class FooConstraint<T> where T : FooType,new(int) // ERROR
public class FooConstraint<T> where T : FooType // usually the constraint is "new()",but I need something like this: new(int) that the compiler verify the CHECK_1
{
}
public sealed class Passed : FooConstraint<FooTypeChildA> //[CHECK_1] Pass the constraint.
{
}
public sealed class NotPassed : FooConstraint<FooTypeChildB> //[CHECK_1] Not Pass the constraint.
{
}
这个指令显示了一个可能的语法异常, new(int arg1)
泛型实例调用构造函数的方式并不重要,因为基本反射在运行时解决了问题,但其想法是强制编译器错误。
ATTEMPT#1 - 这是不可能的;因为接口不能指定构造函数。
public interface IFoo
{
IFoo(int a); // Error here CS0526
}
ATTEMPT#2 - 原始问题已关闭,因为版主专注于在 运行时 级别而不是 编译时 级别解决问题水平。
This Question is not duplicated in this question: 因为 (T)Activator.CreateInstance( typeof(T),args ) 当您需要非常严格的编译检查时不是一个选项.很明显,Activator 没有完成基本原则(必须使用派生类和继承行为,而不是它们的最终实现 - Liskov)保证子类型具有的行为父类型甚至在编译级别。
解决方法
泛型类型中众所周知的约束是 new(),可以添加像 (args,args,...) 这样的参数来强制编译器检查该类是否包含特定的构造函数?
虽然感觉这应该可用,但事实并非如此。您只能为无参数构造函数添加约束。
作为替代方案,考虑传递工厂函数。在这里,您可以指定输入参数。
public class FooConstraint<T> where T : FooType
{
private readonly T _myObject;
public FooConstraint(Func<int,T> generator)
{
_myObject = generator(123);
}
}
注意:您也可以存储 Func
本身,而不是立即使用它并丢弃它。这只是一个例子。
由于 FooConstraint
类定义明确定义了 Func<>
泛型参数,因此您可以确保 FooConstraint
的使用者确切知道您的 FooConstraint
将使用哪些构造函数参数实例化一个 T
实例。
var myConstraint = new FooConstraint<FooTypeChildA>(myInt => new FooTypeChildA(myInt));
因为你总是只调用一个构造函数而不用 Func
做任何花哨的事情,这感觉有点像样板,但考虑到没有真正的泛型参数化构造函数约束,这是最接近的替代。