C#中是否有带参数约束的泛型构造函数?

在C#中,您可以对泛型方法施加约束,如:

public class A {


public static void Method<T> (T a) where T : new() {
//...do something...
}


}

其中,您指定T应具有不需要参数的构造函数。我想知道是否有一种方法可以添加像“是否存在具有float[,]参数的构造函数? ”这样的约束。

以下代码无法编译:

public class A {


public static void Method<T> (T a) where T : new(float[,] u) {
//...do something...
}


}

解决方法也很有用。

102544 次浏览

不。目前,您可以指定的唯一构造函数约束是无参数构造函数。

没有这样的构造。只能指定空的构造函数约束。

我用lambda方法解决了这个问题。

public static void Method<T>(Func<int,T> del) {
var t = del(42);
}

用例

Method(x => new Foo(x));

正如你所发现的,你不能这么做。

作为一种解决方法,我通常提供一个可以创建ABC0__类型的对象的委托:

public class A {


public static void Method<T> (T a, Func<float[,], T> creator) {
//...do something...
}


}

这里有一个我个人认为非常有效的解决方法。如果您认为泛型参数化构造函数约束是什么,那么它实际上是类型和具有特定签名的构造函数之间的映射。您可以使用字典创建自己的映射。把它们放在一个静态的“工厂”类中,你可以创建不同类型的对象,而不必担心每次都要构建构造函数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) }
};

然后在泛型方法中,例如:

   public static T BuildBaseType<T>(...)
where T : BaseType
{
...
T myObject = (T)mTypeConstructors[typeof(T)](value1, value2);
...
return myObject;
}

使用反射创建泛型对象时,类型仍然需要声明正确的构造函数,否则将引发异常。您可以传入任何参数,只要它们与其中一个构造函数匹配。

通过这种方式,您不能对模板中的构造函数施加约束。 如果构造函数缺失,则需要在运行时处理异常,而不是在编译时获取错误。

// 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);

我认为这是最干净的解决方案,它限制了对象的构造方式。它不完全是编译时检查的。当您同意使类的实际构造函数具有与IConstructor接口相同的签名时,这有点像对构造函数的约束。由于显式接口实现,__abc0方法在正常使用对象时是隐藏的。

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;
}
}
}

如何创建带有约束的泛型类,这里我选择了具有值和引用类型的结构和类。

这样,您的构造函数就对值有了约束。

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; }
}

实施:

        MyGenericClass<int, string> intGenericClass = new MyGenericClass<int, string>(10, "Hello world");
int val = intGenericClass.genericMethod(200);

下面是C#维护人员推荐的解决方法。如果您想保持构造函数的参数化,请间接调用构造函数:

            i = (TService)Activator.CreateInstance(typeof(TService), new object[] {arg});

其中tService是一个泛型,它有一个我想保留的参数完整的构造函数。

如果你想了解这种方法是如何工作的: https://learn.microsoft.com/en-us/dotnet/api/system.activator.createinstance?view=net-5.0#system-activator-createinstance(系统-类型-系统-对象-)

AAAA和C#维护人员的讨论: https://github.com/dotnet/csharplang/discussions/769