He estado trabajando en un problema durante un par de horas y creo que estoy cerca. Estoy trabajando en una aplicación donde podríamos tener 50-100 tipos que funcionan de la misma manera. Así que en lugar de crear clases 50-100, traté de hacer que sea genérico y esto es lo que tengo:Crear tipo genérico con interfaz genérica en tiempo de ejecución
Ésta es la clase base:
public class RavenWriterBase<T> : IRavenWriter<T> where T : class, IDataEntity
y esta es la interfaz:
public interface IRavenWriter<T>
{
int ExecutionIntervalInSeconds { get; }
void Execute(object stateInfo);
void Initialize(int executionIntervalInSeconds, Expression<Func<T, DateTime>> timeOrderByFunc);
}
Y así es como lo estoy usando:
private static void StartWriters()
{
Assembly assembly = typeof(IDataEntity).Assembly;
List<IDataEntity> dataEntities = ReflectionUtility.GetObjectsForAnInterface<IDataEntity>(assembly);
foreach (IDataEntity dataEntity in dataEntities)
{
Type dataEntityType = dataEntity.GetType();
Type ravenWriterType = typeof(RavenWriterBase<>).MakeGenericType(dataEntityType);
Expression<Func<IDataEntity, DateTime>> func = x => x.CicReadTime;
// This is where I'm stuck. How do I activate this as RavenWriterBase<T>?
var ravenWriter = Activator.CreateInstance(ravenWriterType);
//ravenWriter.Initialize(60, func); // I can't do this until I cast.
// More functionality here (not part of this issue)
}
}
estoy atascado en esta línea desde arriba:
var ravenWriter = Activator.CreateInstance(ravenWriterType);
Esta es mi pregunta:
¿Cómo puedo usar eso como RavenWriterBase o IRavenWriter? Algo así como:
ravenWriter.Initialize(60, func);
Creo que tiene que ser algo como esto, pero necesito especificar un tipo de IRavenWriter <> y no sé todavía:
var ravenWriter = Activator.CreateInstance(ravenWriterType) as IRavenWriter<>;
Si yo ciernen sobre ravenWriter, tengo éxito mi objeto:
Pero ahora tengo que ser capaz de utilizarlo de una manera genérica. ¿Cómo puedo hacer eso?
Actualización:
me acaba de ocurrir usando la palabra clave dinámica, y esto funciona:
dynamic ravenWriter = Activator.CreateInstance(ravenWriterType);
ravenWriter.Initialize(60);
he engañado un poco porque me di cuenta de que la Func era el mismo para cada IDataEntity, por lo eso no era necesario pasar como parámetro a Initialize(). Sin embargo, al menos ahora I puede llamar a Initialize(). Pero ahora que el Func es el mismo, tampoco debería necesitar la interfaz genérica.
Parece que el uso inadecuado de genéricos. Cuando te encuentras necesitando ejecutar diferentes métodos basados en diferentes tipos, pero los tipos son conocidos solo en tiempo de ejecución, quieres hacer uso del polimorfismo. ¿Qué te está ganando los genéricos? ¿Puede ejecutar los métodos tal como están sin genéricos en primer lugar, es decir, con IDataEntity? – mellamokb
Estoy de acuerdo con mellamokb. Sin embargo, si tiene genéricos, ¿por qué no crear una clase contenedora que pueda crear instancias no genáricamente? El contenedor debería tener un método que devuelva una instancia de RavenWriterBase según el tipo pasado como argumento. A continuación, crea una instancia del contenedor y llama al método con el tipo solicitado como parámetro. Esto requerirá una declaración de interruptor grande, pero al menos no 200 clases separadas. –
dcow
¿Creas otras expresiones que no usan IDataEntity para T? ¿O es T siempre una IDataEntity? Y si T es siempre IDataEntity, ¿por qué usar genéricos? –