¿Hay un constructor genérico con restricción de parámetro en C #?

En C # puedes poner una restricción en un método genérico como:

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

Donde especifica que T debe tener un constructor que no requiere parámetros. Me pregunto si existe una forma de agregar una restricción como “¿ existe un constructor con un parámetro float[,] ?

El siguiente código no se comstack:

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

Una solución alternativa también es útil?

Como has encontrado, no puedes hacer esto.

Como solución alternativa, normalmente proporciono un delegado que puede crear objetos de tipo T :

 public class A { public static void Method (T a, Func creator) { //...do something... } } 

No hay tal construcción. Solo puede especificar una restricción de constructor vacía.

Trabajo alrededor de este problema con los métodos lambda.

 public static void Method(Func del) { var t = del(42); } 

Caso de uso

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

Usando el reflection para crear un objeto genérico, el tipo aún necesita el constructor correcto declarado o se lanzará una excepción. Puede pasar cualquier argumento siempre que coincida con uno de los constructores.

Utilizado de esta manera, no puede poner una restricción en el constructor en la plantilla. Si falta el constructor, se debe manejar una excepción en tiempo de ejecución en lugar de obtener un error en tiempo de comstackción.

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

Aquí hay una solución para esto que personalmente considero bastante efectiva. Si piensas en qué es una restricción de constructor parametrizada genérica, en realidad es una asignación entre tipos y constructores con una firma particular. Puede crear su propia asignación utilizando un diccionario. Póngalos en una clase estática de “fábrica” ​​y puede crear objetos de diferentes tipos sin tener que preocuparse por construir un constructor lambda cada vez:

 public static class BaseTypeFactory { private delegate BaseType BaseTypeConstructor(int pParam1, int pParam2); private static readonly Dictionary mTypeConstructors = new Dictionary { { typeof(Object1), (pParam1, pParam2) => new Object1(pParam1, pParam2) }, { typeof(Object2), (pParam1, pParam2) => new Object2(pParam1, pParam2) }, { typeof(Object3), (pParam1, pParam2) => new Object3(pParam1, pParam2) } }; 

luego en su método genérico, por ejemplo:

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

No. Por el momento, la única restricción de constructor que puede especificar es para un constructor sin argumentos.

Creo que esta es la solución más limpia que pone una restricción en la forma en que se construye un objeto. No se comprueba por completo el tiempo de comstackción. Cuando tiene el acuerdo de hacer que el constructor real de las clases tenga la misma firma, como la interfaz IConstructor, es como tener una restricción en el constructor. El método Constructor está oculto cuando se trabaja normalmente con el objeto, debido a la implementación explícita de la interfaz.

 using System.Runtime.Serialization; namespace ConsoleApp4 { class Program { static void Main(string[] args) { var employeeWorker = new GenericWorker(); employeeWorker.DoWork(); } } public class GenericWorker 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; } } }