2011-01-25 13 views
19

tengo una interfaz (IRepository<T>) que actualmente está siendo extendido para cada repositorio específico, es decir: IUserRepository : IRepository<User>.resuelve automáticamente Interface <T> a Implementación <T> en StructureMap (sólo difieren por tipo T genérico)

Cada una de estas interfaces tiene clases concretas correspondientes, es decir: UserRepository : Repository<User>, IUserRepository.

Estos repositorios individuales no agregan ninguna funcionalidad adicional, son todas interfaces/clases vacías que se utilizan simplemente para pasar los genéricos.

Uso StructureMap para resolver IUserRepository en UserRepository utilizando un Registro con un escáner de ensamblaje y algunas convenciones de nomenclatura.

me gustaría que esto se mueve a una forma de estado más optimizado, donde en lugar de pasar alrededor de las instancias de IUserRepository y conseguir que se resolvió UserRepository, puedo pasar alrededor IRepository<User> y lo han resuelto Repository<User>.

Esto eliminaría la necesidad de crear estas interfaces y clases adicionales vacías.

No puedo encontrar la forma de usar la configuración de StructureMap para configurar este mapeo genérico. Algo como esto:

For(typeof(IRepository<>).Use(typeof(Repository<>)).WithTheGenericTypeFromTheInterfaceSuppliedAsATypeParameter(); 

Editar

Después de conseguir el primer par de respuestas, quiero aclarar esto un poco más.

No deseo crear clases individuales para el bit For de la configuración. Quiero tener las siguientes clases/interfaces en mi código:

  • IRepository<T> where T : Entity
  • Repository<T> : IRepository<T> where T : Entity
  • Person : Entity
  • Product : Entity
  • Order : Entity
  • Whatever : Entity

y tienen las siguientes asignaciones logrado con la convención:

IRepository<Person> => Repository<Person> 
IRepository<Product> => Repository<Product> 
IRepository<Order> => Repository<Order> 
IRepository<Whatever> => Repository<Whatever> 

Pero No quiero tener que crear una asignación para cada uno, Ala:

For<IRepository<Person>>().Use<Repository<Person>>(); 
For<IRepository<Product>>().Use<Repository<Product>>(); 
For<IRepository<Order>>().Use<Repository<Order>>(); 
For<IRepository<Whatever>>().Use<Repository<Whatever>>(); 

Quiero una sola asignación que se trabajar para cualquier IRepository:

For<IRepository<>>().Use<Repository<>>().WithTheSameGenericType(); 

me permitiría usar esto para poner los repositorios en los servicios de:

public MyService(IRepository<User> userRepository) 

Y espera que se resuelva en un Repository<User> en tiempo de ejecución.

+0

Su configuración deseada ya es real (sin la necesidad de WithTheGenericTypeFromTheInterfaceSuppliedAsATypeParameter). ¿Lo intentaste y no funcionó? –

+0

Debo haberlo hecho mal - al principio no compilaría, así que creo que estoy usando la versión genérica del método (aunque cuando escribí la pregunta usé el no genérico). Una de esas mañanas. –

Respuesta

23

Resulta que no hay un método elegante para llamar, o ningún cableado de lujo para hacer, sólo tiene que utilizar For y Use (las versiones no genéricos):

public class DataRegistry : Registry 
{ 
    public DataRegistry() 
    { 
     For(typeof (IRepository<>)).Use(typeof(Repository<>)); 
    } 
} 

Cuando me inyecto una IRepository<Person> que se resuelve como un no Repository<Person> w.

Encontré el error 104 diciendo que Repository no se podía conectar para IRepository. Esto se debió a que el repositorio se marcó como abstract. Hacerlo no abstracto solucionó ese error y funciona como se desea.

+0

Eso es bueno saber, ahorrará mucha configuración. – CRice

+0

Con esta configuración, ¿cómo agregaría un método específico para, por ejemplo, el Repositorio , es decir, AllByLastName() ??? ¿O solo estás devolviendo IQueryable? – Paul

+0

Simplemente devolviendo IQueryable. La lógica específica del dominio como AllByLastName se encuentra en nuestra capa de servicios. Repo tiene get, delete, query, upsert etc. –

0

Eche un vistazo a la interfaz IRegistrationConvention.

public class DomainRegistry : Registry 
{ 
    public DomainRegistry() 
     : base() 
    { 
     Scan(y => 
     { 
      y.AssemblyContainingType<IRepository>(); 
      y.Assembly(Assembly.GetExecutingAssembly().FullName); 
      y.With(new RepositoryTypeScanner()); 
     }); 

Dónde RepositoryTypeScanner:

public class RepositoryTypeScanner : IRegistrationConvention 
{ 
    public void Process(Type type, Registry registry) 
    { 
     ... 
+0

Gracias, pero eso realmente no resuelve el problema. Ya estoy usando un escáner de tipo y usando convenciones de nomenclatura para cablear cualquier tipo concreto a su interfaz correspondiente. Sin embargo, quiero eliminar todas esas interfaces y tipos de concreto y tener structuremap pasar automáticamente el parámetro genérico entre 'IRepository ' y 'Repository '. –

1

Este es un ejemplo. El mapa de estructura le permitirá hacer ambas cosas también.

//IRepository 
For<IMemberRepository>().Add<MemberRepository>(); 

//IRepository<T> 
For<IRepository<Member>>().Add<MemberRepository>(); 

entonces es útil para pedir los tipos por el hecho de saber el tipo genérico en tiempo de ejecución:

Type repositoryType = typeof(IRepository<>).MakeGenericType(modelType); 
IocResolve.Resolve(repositoryType); 
+0

Gracias - Creo que mi pregunta es un poco confusa. Lo actualizaré en breve. Estoy tratando de encontrar una solución para no tener que crear una clase 'MemberRepository', sino tener' IRepository 'mapeado a' Repository 'con una convención. –

+0

¿Cuántas líneas de configuración individuales imagina que va a ahorrar con esto? ¿Tienes tantas clases? – CRice

+0

Diferentes repositorios? Sí un poco. Pero se trata más bien de no tener que crear las clases individuales de IXXXREpository y XXXRepository, ya que están vacías y se usan simplemente para la resolución de tipo genérico.En lugar de tener que crear la entidad, crear una interfaz, crear una clase, editar el registro y luego usar la nueva interfaz, sería mejor para todos simplemente crear la entidad y usar 'IRepository '. Mucho menos trabajo. –

4

sugiero que eche un vistazo al método AddAllTypesOf. Tenía un código similar y logré mis objetivos al usarlo (y mantuve funcionando la función de registro automático).

En su caso, sólo debe cambiar

For<IRepository<Person>>().Use<Repository<Person>>(); 
For<IRepository<Product>>().Use<Repository<Product>>(); 
For<IRepository<Order>>().Use<Repository<Order>>(); 
For<IRepository<Whatever>>().Use<Repository<Whatever>>(); 

a

AddAllTypesOf(typeof(IRepository<>)); 

Al final, el contenedor será similar a:

return new Container(x => 
     { 
      x.Scan(y => 
      { 
       y.TheCallingAssembly(); 
       y.AddAllTypesOf(typeof(IRepository<>)); 
       y.WithDefaultConventions(); 
      }); 
     }); 
+0

Tyron, resolviste un problema de larga duración en mi mundo. GRACIAS. –

+1

Solo para observar, hay algunos momentos en los que la clase genérica depende de dos o más clases (como los Mappers, por ejemplo). En ese caso, solo use el formulario: 'y.AddAllTypesOf (typeof (IMapper <,>))' – tyron

Cuestiones relacionadas