usando tipo ser reutilizacion restricciones referencia permiten metodos genericos genericas declaraciones debe constructores colecciones codigo c# generics parameters constructor generic-constraints

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



reutilizacion de codigo en c# (6)

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

public class A { public static void Method<T> (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 compila:

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

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


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

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

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


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> (T a, Func<float[,], T> creator) { //...do something... } }


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


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<T>(Func<int,T> del) { var t = del(42); }

Caso de uso

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


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


Usando el reflejo 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 compilació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);