tipos - Genéricos en C#, usando el tipo de una variable como parámetro
variables alfanumericas en c# (4)
Esta pregunta ya tiene una respuesta aquí:
Tengo un método genérico
bool DoesEntityExist<T>(Guid guid, ITransaction transaction) where T : IGloballyIdentifiable;
¿Cómo uso el método de la siguiente manera?
Type t = entity.GetType();
DoesEntityExist<t>(entityGuid, transaction);
Sigo recibiendo el siguiente error de compilación:
No se pudo encontrar el tipo o el nombre del espacio de nombres ''t'' (¿falta una directiva using o una referencia de ensamblado?)
DoesEntityExist<MyType>(entityGuid, transaction);
funciona perfectamente pero no quiero usar una directiva if para llamar al método con un nombre de tipo diferente cada vez.
El objetivo de los genéricos es proporcionar seguridad de tipo de tiempo de compilación , lo que significa que los tipos deben conocerse en tiempo de compilación.
Puede llamar a métodos genéricos con tipos conocidos solo en tiempo de ejecución, pero debe usar la reflexión:
// For non-public methods, you''ll need to specify binding flags too
MethodInfo method = GetType().GetMethod("DoesEntityExist")
.MakeGenericMethod(new Type[] { t });
method.Invoke(this, new object[] { entityGuid, transaction });
Ick.
¿Puede hacer que su método de llamada sea genérico en su lugar, y pasar su parámetro de tipo como el argumento de tipo, empujando la decisión un nivel más arriba en la pila?
Si pudieras darnos más información sobre lo que estás haciendo, eso sería útil. A veces puede necesitar usar el reflejo como se indicó anteriormente, pero si selecciona el punto correcto para hacerlo, puede asegurarse de que solo necesita hacerlo una vez, y dejar que todo debajo de ese punto use el parámetro tipo de una manera normal.
No estoy seguro de si entiendo su pregunta correctamente, pero puede escribir su código de esta manera:
bool DoesEntityExist<T>(T instance, ....)
Puede llamar al método de la siguiente manera:
DoesEntityExist(myTypeInstance, ...)
De esta manera, no es necesario que escriba explícitamente el tipo, el marco superará automáticamente el tipo de la instancia.
No puedes usarlo de la manera que describes. El punto acerca de los tipos genéricos es que, aunque es posible que no los conozca en el "tiempo de codificación", el compilador debe poder resolverlos en tiempo de compilación. ¿Por qué? Debido a que bajo el capó, el compilador se irá y creará un nuevo tipo (a veces llamado tipo genérico cerrado) para cada uso diferente del tipo genérico "abierto".
En otras palabras, después de la compilación,
DoesEntityExist<int>
es un tipo diferente de
DoesEntityExist<string>
Así es como el compilador puede anticipar la seguridad del tipo de compilación.
Para el escenario que describe, debe pasar el tipo como un argumento que puede examinarse en tiempo de ejecución.
La otra opción, como se menciona en otras respuestas, es usar el reflejo para crear el tipo cerrado del tipo abierto, aunque esto probablemente se recomienda en cualquier otra cosa que los escenarios extremos de nicho, diría yo.
Una forma de evitar esto es usar conversión implícita:
bool DoesEntityExist<T>(T entity, Guid guid, ITransaction transaction) where T : IGloballyIdentifiable;
llamándolo así:
DoesEntityExist(entity, entityGuid, transaction);
Yendo un paso más allá, puede convertirlo en un método de extensión (deberá declararse en una clase estática):
static bool DoesEntityExist<T>(this T entity, Guid guid, ITransaction transaction) where T : IGloballyIdentifiable;
llamando así:
entity.DoesEntityExist(entityGuid, transaction);