简体   繁体   English

autofac:如何解决命名类型的集合?

[英]autofac: How to resolve collection of named types?

I have a bunch of TaskParametes class instances registered in container, like: 我在容器中注册了一堆TaskParametes类实例,如:

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

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

These classes can be registered in any module of the application. 这些类可以在应用程序的任何模块中注册。 I'd like to get the list of available named instances to sent it to client, which should instantiate and execute it by name. 我想获取可用的命名实例列表以将其发送到客户端,客户端应该按名称实例化并执行它。

Is there an option to get the list of the names, without actually instantiating types? 是否有选项可以获取名称列表,而无需实际实例化类型? Currently I'm digging ComponentRegistry of IComponentContext, which I get from, var ctx = Container.Resolve<IComponentContext>(); 目前我正在挖掘IComponentContext的ComponentRegistry,我得到了它, var ctx = Container.Resolve<IComponentContext>(); , am I on the right direction? 我正朝着正确的方向前进吗?

Metadata is more appropriate than naming in this case. 在这种情况下,元数据比命名更合适。

For the strongly-typed variant, define an interface to hold the metadata: 对于强类型变体,定义用于保存元数据的接口:

public interface ITaskMetadata
{
    string Name { get; }
}

Then associate the metadata at build time: 然后在构建时关联元数据:

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"));

(The InstancePerDependency() is omitted because it is the default behaviour.) (省略InstancePerDependency() ,因为它是默认行为。)

Then, the component that needs to examine the names can take a dependency on IEnumerable<Lazy<T,TMetadata>> like so: 然后,需要检查名称的组件可以依赖于IEnumerable<Lazy<T,TMetadata>>如下所示:

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

This uses relationship types to avoid the need to look anything up in the container. 这使用关系类型来避免在容器中查找任何内容。

Note, the Lazy<,> type is from .NET 4. For details on achieving this in .NET 3.5, and alternative syntax, see the Autofac wiki . 注意, Lazy<,>类型来自.NET 4.有关在.NET 3.5中实现此功能的详细信息以及替代语法,请参阅Autofac wiki

If the name of the service is important to your application, maybe that should be modeled into your code. 如果服务名称对您的应用程序很重要,那么可能应该将其建模到您的代码中。 For example, you have TaskParameters ; 例如,您有TaskParameters ; maybe you want something like: 也许你想要的东西:

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(); }
}

And then you can register descriptors for your types. 然后,您可以为您的类型注册描述符。 Then you could easily call 然后你可以轻松打电话

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

I did'n find any solution rather than querying the context: 我找不到任何解决方案而不是查询上下文:

    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();

It seems that this approach doesn't instantiate nor activate anything. 似乎这种方法不会实例化也不会激活任何东西。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM