c# - pueden - ¿Cómo usar Activator para crear una instancia de un Tipo genérico y devolverlo a ese tipo?
cuantos hashtags se pueden poner en instagram 2018 (5)
¿No puedes envolverlo?
algo como
public Store<T> IConstructStore<T>(T item) where T : IStorable
{
return Activator.CreateInstance(typeof(Store<T>), new object[] { someParameter }) as Store<T>;
}
o me estoy perdiendo lo que estás tratando de hacer?
ES DECIR
class Program
{
static void Main(string[] args)
{
Beer b = new Beer();
var beerStore = IConstructStore(b);
Console.WriteLine(beerStore.test);
Console.WriteLine(beerStore.GetType().ToString());
}
public static Store<T> IConstructStore<T>(T item) where T : IStorable
{
return Activator.CreateInstance(typeof(Store<T>), new object[] { }) as Store<T>;
}
}
interface IStorable { }
class Store<T> where T : IStorable
{
public int test = 1;
}
class Beer : IStorable
{ }
huellas dactilares
1
ConsoleApp1.Store''1[ConsoleApp1.Beer]
Tengo un tipo genérico Store<T>
y uso Activator
para hacer una instancia de este tipo. Ahora, ¿cómo, después de usar el activador, puedo convertir el objeto resultante del tipo de object
al tipo instanciado? Sé el tipo que utilicé para crear una instancia del genérico. Por favor mira el siguiente código:
class Store<T> where T : IStorable
{}
class Beer : IStorable
{}
class BeerStore : Store<Beer>
{}
Type storeType = someObjectThatImplementsIStorable.GetType();
Type classType = typeof(Store<>);
Type[] typeParams = new Type[] { storeType };
Type constructedType = classType.MakeGenericType(typeParams);
object x = Activator.CreateInstance(constructedType, new object[] { someParameter });
Lo que me gustaría hacer es algo como esto:
var store = (Store<typeof(objectThatImplementsIStorable)>)x;
pero eso no funciona por razones obvias. Como alternativa, intenté:
var store = (Store<IStorable>)x;
que posiblemente podría funcionar en mi opinión, pero da una InvalidCastException
.
¿Cómo vuelvo a acceder a los métodos Store<T>
que sé que están en el objeto x
?
Dado que el tipo real T
está disponible para ti solo mediante reflexión, necesitarás acceder a los métodos de Store<T>
través de la reflexión también:
Type constructedType = classType.MakeGenericType(typeParams);
object x = Activator.CreateInstance(constructedType, new object[] { someParameter });
var method = constructedType.GetMethod("MyMethodTakingT");
var res = method.Invoke(x, new object[] {someObjectThatImplementsStorable});
EDITAR También podría definir una interfaz de IStore
adicional que no utiliza genéricos, y utiliza IStorable
en IStorable
lugar:
interface IStore {
int CountItems(IStorable item);
}
class Store<T> : IStore where T : IStorable {
int CountItems(IStorable item) {
return count;
}
}
Su Store<T>
se mantendría genérica, pero tendría acceso a sus CountItems
de CountItems
mediante conversión a IStore
:
var x = (IStore)Activator.CreateInstance(constructedType, new object[] { someParameter });
var count = x.CountItems((IStorable)someObjectThatImplementsStorable);
Digamos que someObjectThatImplementsIStorable es del tipo MyStorable.
por ejemplo, MyStorable someObjectThatImplementsIStorable = new MyStorable (); ... // resto de tu código aquí.
Entonces x no se puede convertir a Store, pero se puede convertir a Store. Lo siguiente funcionará: (Tienda) x
Tenga en cuenta que aunque MyStorable implementa IStorable, no hay relación entre Tienda y Tienda. Estas son dos clases distintas que no se derivan una de la otra.
tú
La respuesta más adecuada en mi opinión sería ''no puedes hacerlo de esta manera''.
Puede intentar introducir una interfaz IStorage
e intentar que sea covariante o contravariante (¿ha visto esa opción?). Si no es una opción, por ejemplo, si tiene tanto genéricos de entrada como de salida utilizados en Storage
, entonces no hay forma de implementar lo que desea. La razón es que Storage<Beer>
no se puede usar de forma segura como Storage<IStorable>
debido a este caso:
Storage<IStorable> store = new Storage<Beer>(); // let''s pretend we can do it
store.Save(new StorableButNotBeer()); // what will happen here?
La única solución posible para ti, como yo lo veo, es mover el casting desde este método y lanzar el objeto al lugar donde conoces todos los tipos exactos:
public void object CreateStore(Type istorableType)
{
// here is your activator code, but you will have to return an object
}
var beerStore = (Store<Beer>)CreateStore(typeof(Beer));
T debe ser el tipo Store evitando el uso de typeof (Store