C# 中是否有带参数约束的泛型构造函数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1852837/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is there a generic constructor with parameter constraint in C#?
提问by Willem Van Onsem
In C# you can put a constraint on a generic method like:
在 C# 中,您可以对泛型方法施加约束,例如:
public class A {
public static void Method<T> (T a) where T : new() {
//...do something...
}
}
Where you specify that T
should have a constructor that requires no parameters. I'm wondering whether there is a way to add a constraint like "there exists a constructor with a float[,]
parameter?"
您指定的地方T
应该有一个不需要参数的构造函数。我想知道是否有办法添加约束,例如“存在带有float[,]
参数的构造函数?”
The following code doesn't compile:
以下代码无法编译:
public class A {
public static void Method<T> (T a) where T : new(float[,] u) {
//...do something...
}
}
A workaround is also useful?
解决方法也有用吗?
采纳答案by Tim Robinson
As you've found, you can't do this.
正如你所发现的,你不能这样做。
As a workaround I normally supply a delegate that can create objects of type T
:
作为一种解决方法,我通常提供一个可以创建类型对象的委托T
:
public class A {
public static void Method<T> (T a, Func<float[,], T> creator) {
//...do something...
}
}
回答by Sean Reilly
No. At the moment the only constructor constraint you can specify is for a no-arg constructor.
不。目前您可以指定的唯一构造函数约束是无参数构造函数。
回答by JaredPar
There is no such construct. You can only specify an empty constructor constraint.
没有这样的构造。您只能指定一个空的构造函数约束。
I work around this problem with lambda methods.
我用 lambda 方法解决了这个问题。
public static void Method<T>(Func<int,T> del) {
var t = del(42);
}
Use Case
用例
Method(x => new Foo(x));
回答by Dave Cousineau
Here is a workaround for this that I personally find quite effective. If you think of what a generic parameterized constructor constraint is, it's really a mapping between types and constructors with a particular signature. You can create your own such mapping by using a dictionary. Put these in a static "factory" class and you can create objects of varying type without having to worry about building a constructor lambda every time:
这是我个人认为非常有效的解决方法。如果您考虑什么是泛型参数化构造函数约束,它实际上是具有特定签名的类型和构造函数之间的映射。您可以使用字典创建自己的此类映射。将它们放在静态“工厂”类中,您可以创建不同类型的对象,而不必担心每次都构建构造函数 lambda:
public static class BaseTypeFactory
{
private delegate BaseType BaseTypeConstructor(int pParam1, int pParam2);
private static readonly Dictionary<Type, BaseTypeConstructor>
mTypeConstructors = new Dictionary<Type, BaseTypeConstructor>
{
{ typeof(Object1), (pParam1, pParam2) => new Object1(pParam1, pParam2) },
{ typeof(Object2), (pParam1, pParam2) => new Object2(pParam1, pParam2) },
{ typeof(Object3), (pParam1, pParam2) => new Object3(pParam1, pParam2) }
};
then in your generic method, for example:
然后在您的通用方法中,例如:
public static T BuildBaseType<T>(...)
where T : BaseType
{
...
T myObject = (T)mTypeConstructors[typeof(T)](value1, value2);
...
return myObject;
}
回答by xpress
Using reflection to create a generic object, the type still needs the correct constructor declared or an exception will be thrown. You can pass in any argument as long as they match one of the constructors.
使用反射创建泛型对象,该类型仍然需要声明正确的构造函数,否则将引发异常。您可以传入任何参数,只要它们与构造函数之一匹配即可。
Used this way you cannot put a constraint on the constructor in the template. If the constructor is missing, an exception needs to be handled at run-time rather than getting an error at compile time.
使用这种方式,您不能对模板中的构造函数施加约束。如果缺少构造函数,则需要在运行时处理异常,而不是在编译时出错。
// public static object CreateInstance(Type type, params object[] args);
// Example 1
T t = (T)Activator.CreateInstance(typeof(T));
// Example 2
T t = (T)Activator.CreateInstance(typeof(T), arg0, arg1, arg2, ...);
// Example 3
T t = (T)Activator.CreateInstance(typeof(T), (string)arg0, (int)arg1, (bool)arg2);
回答by Mike de Klerk
I think this is the most clean solution that kind of puts a constraint on the way an object is constructed. It is not entirely compile time checked. When you have the agreement to make the actual constructor of the classes have the same signature like the IConstructor interface, it is kind of like having a constraint on the constructor. The Constructor
method is hidden when working normally with the object, because of the explicit interface implementation.
我认为这是对对象构造方式施加限制的最干净的解决方案。它没有完全检查编译时。当您同意使类的实际构造函数具有与 IConstructor 接口相同的签名时,这有点像对构造函数施加约束。Constructor
由于显式接口实现,该方法在与对象正常工作时是隐藏的。
using System.Runtime.Serialization;
namespace ConsoleApp4
{
class Program
{
static void Main(string[] args)
{
var employeeWorker = new GenericWorker<Employee>();
employeeWorker.DoWork();
}
}
public class GenericWorker<T> where T:IConstructor
{
public void DoWork()
{
T employee = (T)FormatterServices.GetUninitializedObject(typeof(T));
employee.Constructor("John Doe", 105);
}
}
public interface IConstructor
{
void Constructor(string name, int age);
}
public class Employee : IConstructor
{
public string Name { get; private set; }
public int Age { get; private set; }
public Employee(string name, int age)
{
((IConstructor)this).Constructor(name, age);
}
void IConstructor.Constructor(string name, int age)
{
Name = name;
Age = age;
}
}
}
回答by Pierre-David Sabourin
How about creating your generic class with constraints, here I chose struct and class to have value and reference types.
如何创建带有约束的泛型类,这里我选择了 struct 和 class 来具有值和引用类型。
That way your constructor has a constraint on the values.
这样你的构造函数就对值有约束。
class MyGenericClass<T, X> where T :struct where X: class { private T genericMemberVariableT; private X genericMemberVariableX; public MyGenericClass(T valueT, X valueX) { genericMemberVariableT = valueT; genericMemberVariableX = valueX; } public T genericMethod(T genericParameter) { Console.WriteLine("Parameter type: {0}, value: {1}", typeof(T).ToString(), genericParameter); Console.WriteLine("Return type: {0}, value: {1}", typeof(T).ToString(), genericMemberVariableT); Console.WriteLine("Return type: {0}, value: {1}", typeof(X).ToString(), genericMemberVariableX); return genericMemberVariableT; } public T genericProperty { get; set; } }
class MyGenericClass<T, X> where T :struct where X: class { private T genericMemberVariableT; private X genericMemberVariableX; public MyGenericClass(T valueT, X valueX) { genericMemberVariableT = valueT; genericMemberVariableX = valueX; } public T genericMethod(T genericParameter) { Console.WriteLine("Parameter type: {0}, value: {1}", typeof(T).ToString(), genericParameter); Console.WriteLine("Return type: {0}, value: {1}", typeof(T).ToString(), genericMemberVariableT); Console.WriteLine("Return type: {0}, value: {1}", typeof(X).ToString(), genericMemberVariableX); return genericMemberVariableT; } public T genericProperty { get; set; } }
Implementation:
执行:
MyGenericClass<int, string> intGenericClass = new MyGenericClass<int, string>(10, "Hello world"); int val = intGenericClass.genericMethod(200);
MyGenericClass<int, string> intGenericClass = new MyGenericClass<int, string>(10, "Hello world"); int val = intGenericClass.genericMethod(200);