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

发布于 11-03 06:06 字数 566 浏览 2 评论 0 原文

我在容器中注册了一堆 TaskParametes 类实例,例如:

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

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

这些类可以在应用程序的任何模块中注册。我想获取可用命名实例的列表,并将其发送给客户端,客户端应按名称实例化并执行它。

是否有一个选项可以获取名称列表,而无需实际实例化类型? 目前我正在挖掘 IComponentContext 的 ComponentRegistry,它是从 var ctx = Container.Resolve(); 获得的,我的方向正确吗?

I have a bunch of TaskParametes class instances registered in container, like:

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>();, am I on the right direction?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

小帐篷 2024-11-10 06:06:19

在这种情况下,元数据比命名更合适。

对于强类型变体,定义一个接口来保存元数据:

public interface ITaskMetadata
{
    string Name { get; }
}

然后在构建时关联元数据:(

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

InstancePerDependency() 被省略,因为它是默认行为。)

然后,组件需要检查名称可以依赖 IEnumerable>,如下所示:

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

这使用 关系类型以避免需要在容器中查找任何内容。

请注意,Lazy<,> 类型来自 .NET 4。有关在 .NET 3.5 中实现此目的的详细信息以及替代语法,请参阅 Autofac 维基

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.)

Then, the component that needs to examine the names can take a dependency on IEnumerable<Lazy<T,TMetadata>> like so:

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.

一萌ing 2024-11-10 06:06:19

如果服务名称对您的应用程序很重要,也许应该将其建模到您的代码中。例如,您有 TaskParameters;也许你想要这样的东西:

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

然后你可以为你的类型注册描述符。然后你就可以轻松调用

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

If the name of the service is important to your application, maybe that should be modeled into your code. For example, you have 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>>>();
作妖 2024-11-10 06:06:19

我没有找到任何解决方案,而不是查询上下文:

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

似乎这种方法不会实例化或激活任何内容。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文