usar una referente que objetos metodos llamar instancia ejemplos cuando crear como clases clase ambito c# .net generics

una - metodos de instancia c#



Crear instancia de tipo genérico? (8)

Además, un ejemplo más simple:

return (T)Activator.CreateInstance(typeof(T), new object[] { weight });

Tenga en cuenta que el uso de la nueva () restricción en T es solo para hacer que el compilador verifique la existencia de un constructor público sin parámetros en tiempo de compilación, el código real utilizado para crear el tipo es la clase Activator.

Tendrá que asegurarse del constructor específico existente, y este tipo de requisito puede ser un olor a código (o más bien algo que debería tratar de evitar en la versión actual en c #).

Si BaseFruit tiene un constructor que acepta un int weight , ¿puedo crear una instancia de una fruta en un método genérico como este?

public void AddFruit<T>()where T: BaseFruit{ BaseFruit fruit = new T(weight); /*new Apple(150);*/ fruit.Enlist(fruitManager); }

Se agrega un ejemplo detrás de los comentarios. Parece que solo puedo hacer esto si le doy a BaseFruit un constructor sin parámetros y luego lleno todo a través de las variables de los miembros. En mi código real (no sobre la fruta) esto es bastante poco práctico.

-Actualizar-
Entonces parece que no puede ser resuelto por restricciones de ninguna manera. De las respuestas hay tres soluciones candidatas:

  • Patrón de fábrica
  • Reflexión
  • Activador

Tiendo a pensar que el reflejo es el menos limpio, pero no puedo decidir entre los otros dos.


Como Jon señaló, esta es la vida para restringir a un constructor sin parámetros. Sin embargo, una solución diferente es usar un patrón de fábrica. Esto es fácilmente restringible

interface IFruitFactory<T> where T : BaseFruit { T Create(int weight); } public void AddFruit<T>( IFruitFactory<T> factory ) where T: BaseFruit { BaseFruit fruit = factory.Create(weight); /*new Apple(150);*/ fruit.Enlist(fruitManager); }

Otra opción más es usar un enfoque funcional. Pase en un método de fábrica.

public void AddFruit<T>(Func<int,T> factoryDel) where T : BaseFruit { BaseFruit fruit = factoryDel(weight); /* new Apple(150); */ fruit.Enlist(fruitManager); }


La solución más simple Activator.CreateInstance<T>()


No puedes usar ningún constructor con parámetros. Puede usar un constructor sin parámetros si tiene una restricción " where T : new() ".

Es un dolor, pero así es la vida :(

Esta es una de las cosas que me gustaría abordar con "interfaces estáticas" . Entonces podría restringir T para incluir métodos estáticos, operadores y constructores, y luego llamarlos.


Puedes hacerlo mediante el uso de la reflexión:

public void AddFruit<T>()where T: BaseFruit { ConstructorInfo constructor = typeof(T).GetConstructor(new Type[] { typeof(int) }); if (constructor == null) { throw new InvalidOperationException("Type " + typeof(T).Name + " does not contain an appropriate constructor"); } BaseFruit fruit = constructor.Invoke(new object[] { (int)150 }) as BaseFruit; fruit.Enlist(fruitManager); }

EDITAR: constructor agregado == verificación nula.

EDITAR: una variante más rápida que usa un caché:

public void AddFruit<T>()where T: BaseFruit { var constructor = FruitCompany<T>.constructor; if (constructor == null) { throw new InvalidOperationException("Type " + typeof(T).Name + " does not contain an appropriate constructor"); } var fruit = constructor.Invoke(new object[] { (int)150 }) as BaseFruit; fruit.Enlist(fruitManager); } private static class FruitCompany<T> { public static readonly ConstructorInfo constructor = typeof(T).GetConstructor(new Type[] { typeof(int) }); }


Recientemente me encontré con un problema muy similar. Solo quería compartir nuestra solución con todos ustedes. Quería crear una instancia de un Car<CarA> desde un objeto json usando una enumeración:

Dictionary<MyEnum, Type> mapper = new Dictionary<MyEnum, Type>(); mapper.Add(1, typeof(CarA)); mapper.Add(2, typeof(BarB)); public class Car<T> where T : class { public T Detail { get; set; } public Car(T data) { Detail = data; } } public class CarA { public int PropA { get; set; } public CarA(){} } public class CarB { public int PropB { get; set; } public CarB(){} } var jsonObj = {"Type":"1","PropA":"10"} MyEnum t = GetTypeOfCar(jsonObj); Type objectT = mapper[t] Type genericType = typeof(Car<>); Type carTypeWithGenerics = genericType.MakeGenericType(objectT); Activator.CreateInstance(carTypeWithGenerics , new Object[] { JsonConvert.DeserializeObject(jsonObj, objectT) });


Sí; cambia tu lugar donde estar:

where T:BaseFruit, new()

Sin embargo, esto solo funciona con constructores sin parámetros . Deberá tener otros medios para configurar su propiedad (establecer la propiedad en sí o algo similar).


Todavía es posible, con un alto rendimiento, haciendo lo siguiente:

// public List<R> GetAllItems<R>() where R : IBaseRO, new() { var list = new List<R>(); using ( var wl = new ReaderLock<T>( this ) ) { foreach ( var bo in this.items ) { T t = bo.Value.Data as T; R r = new R(); r.Initialize( t ); list.Add( r ); } } return list; }

y

// ///<summary>Base class for read-only objects</summary> public partial interface IBaseRO { void Initialize( IDTO dto ); void Initialize( object value ); }

Las clases relevantes deben derivarse de esta interfaz e inicializarse en consecuencia. Tenga en cuenta que, en mi caso, este código es parte de una clase circundante, que ya tiene <T> como parámetro genérico. R, en mi caso, también es una clase de solo lectura. IMO, la disponibilidad pública de las funciones de Initialize () no tiene un efecto negativo en la inmutabilidad. El usuario de esta clase podría incluir otro objeto, pero esto no modificaría la colección subyacente.