2011-04-25 10 views
7

I tienen un grupo de instancias de la clase TaskParametes registrados en el recipiente, como:autofac: ¿Cómo resolver la colección de tipos con nombre?

builder.Register(c => [some type instantiation] 
    )).Named<TaskParameters>("someTask").InstancePerDependency(); 

builder.Register(c => [some type instantiation] 
    )).Named<TaskParameters>("someOtherTask").InstancePerDependency(); 

Estas clases pueden ser registrados en cualquiera de los módulos de la aplicación. Me gustaría obtener la lista de instancias con nombre disponibles para enviarlo al cliente, que debe crear una instancia y ejecutarlo por su nombre.

¿Existe una opción para obtener la lista de los nombres, sin realmente crear instancias de tipos? Actualmente estoy excavando ComponentRegistry of IComponentContext, que obtengo de, var ctx = Container.Resolve<IComponentContext>();, ¿estoy en la dirección correcta?

Respuesta

4

Metadatos es más apropiado que nombrar en este caso.

Para la variante de tipado fuerte, definir una interfaz para mantener los metadatos:

public interface ITaskMetadata 
{ 
    string Name { get; } 
} 

asociar entonces los metadatos en tiempo de compilación:

builder.Register(c => [some type instantiation])) 
    .As<TaskParameters>() 
    .WithMetadata<ITaskMetadata>(m => 
     m.For(tm => tm.Name, "someTask")); 

builder.Register(c => [some type instantiation])) 
    .As<TaskParameters>() 
    .WithMetadata<ITaskMetadata>(m => 
     m.For(tm => tm.Name, "someOtherTask")); 

(se omite el InstancePerDependency() porque es el comportamiento predeterminado.)

Luego, el componente que necesita para examinar los nombres puede tomar una dependencia en IEnumerable<Lazy<T,TMetadata>> como tal:

class SomeComponent : ISomeComponent 
{ 
    public SomeComponent(
     IEnumerable<Lazy<TaskParameters,ITaskMetadata>> parameters) 
    { 
     // Here the names can be examined without causing instantiation. 
    } 
} 

Esto usa relationship types para evitar la necesidad de buscar algo en el contenedor.

Nota, el tipo Lazy<,> es de .NET 4. Para obtener más información sobre cómo lograr esto en .NET 3.5 y la sintaxis alternativa, consulte el Autofac wiki.

+0

El problema con los metadatos es que no puedo consultarlo desde el contenedor (hay 'ResolveNamed' y' ResolveKeyed', pero no resove por metadatos). Tampoco puedo encontrar la extensión "Para", ¿está en algún espacio de nombres especial? (AutoFac versión 2.4.4.705) – ikutsin

+1

Intellisense (¿ReSharper?) Tiene problemas con el método WithMetadata, aún debe compilarse. Si también desea resolver estos manejadores desde el contenedor, por favor publique algunos detalles de ese escenario, su pregunta solo habla de crear instancias delegando a los clientes. Para rápido y sucio, se puede usar Named() y WithMetadata(). ¡Aclamaciones! –

1

Si el nombre del servicio es importante para su aplicación, tal vez debería ser modelado en su código. Por ejemplo, tiene TaskParameters; tal vez quiere algo como:

public class Descriptor<T> 
{ 
    private readonly string _description; 
    private readonly Func<T> _create; 

    public Descriptor(string description, Func<T> create) 
    { 
     _description = description; 
     _create = create; 
    } 

    public string Description { get { return _description; } } 
    public T Create() { return _create(); } 
} 

Y entonces usted puede inscribirse descriptores para sus tipos. A continuación, puede llamar fácilmente al

var descriptors = container.Resolve<IEnumerable<Descriptor<TaskParameters>>>(); 
0

I did'n encontrar ninguna solución en lugar de consultar el contexto:

var ctx = Container.Resolve<IComponentContext>(); 
    var taskNames = ctx.ComponentRegistry.Registrations 
     .Select(c => c.Services.FirstOrDefault() as KeyedService) 
     .Where(s => s != null && s.ServiceType == typeof (TaskParameters)) 
     .Select(s => s.ServiceKey).ToList(); 

Parece que este enfoque no instanciar ni activar nada.

+0

??? Entonces, ¿esta no es una respuesta para nada? – barrypicker

Cuestiones relacionadas