【问题标题】:Pass an object to multiple IServiceCollection Extensions将一个对象传递给多个 IServiceCollection 扩展
【发布时间】:2022-11-02 03:40:59
【问题描述】:

我需要将一个对象传递给我创建的几个IServiceCollection 扩展,并且我的所有扩展方法都使用该对象并注册它们相关的依赖项。下面是我的代码的样子:

程序.cs

var myObject = new MyObject(); //MyObject implements IMyObject
var builder = WebApplication.CreateBuilder(args);
builder.Services
       .AddMyExtension1(myObject)
       .AddMyExtension2(myObject)
       .AddMyExtension3(myObject)
       ...
       .AddMyExtensionN(myObject);

var app = builder.Build();
...
app.Run();

示例扩展:

public static class MyExtensions{

  public static IServiceCollection AddMyExtension1(
        this IServiceCollection services,
        IMyObject myObject)
  {
     //do something
     //register some dependencies
     return services;
  }
}

我知道使用BuildServiceProvider 可能会导致代码异味/“导致创建单例服务的额外副本”。谁能推荐一种更好的方法来在我的扩展方法中使用 myObject 实例,而不是在我的所有方法中将其作为参数传递?

【问题讨论】:

    标签: c# asp.net-core .net-6.0


    【解决方案1】:

    如果没有看到myObject 的实际用法,很难争论什么是最好的方法。如果所有自定义 AddMyExtension.. 方法都需要它,则可能应该在运行时注入和解析以进行相应的注册。

    如果在您的情况下不可能或只是个坏主意,您可以创建一个新接口,其实现基本上是 IServiceCollection 的包装器,并将其用于注册。像这样的东西:

    public interface IMyServiceCollection : IServiceCollection
    {
        public IMyObject MyObject { get; }
    }
    
    class MyServiceCollection : IMyServiceCollection
    {
        private readonly IServiceCollection _serviceCollection;
    
        public IMyObject MyObject { get; }
    
        public MyServiceCollection(IServiceCollection serviceCollection, IMyObject myObject)
        {
            _serviceCollection = serviceCollection;
            MyObject = myObject;
        }
    
        public IEnumerator<ServiceDescriptor> GetEnumerator() => _serviceCollection.GetEnumerator();
    
        IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)_serviceCollection).GetEnumerator();
    
        public void Add(ServiceDescriptor item) => _serviceCollection.Add(item);
    
        public void Clear() => _serviceCollection.Clear();
    
        public bool Contains(ServiceDescriptor item) => _serviceCollection.Contains(item);
    
        public void CopyTo(ServiceDescriptor[] array, int arrayIndex) => _serviceCollection.CopyTo(array, arrayIndex);
    
        // the rest of IServiceCollection delegating implementation ...
    }
    

    扩展:

    public static class ServicesExts
    {  
        public static IMyServiceCollection WithMyObject(this IServiceCollection services, IMyObject obj) => new MyServiceCollection(services, obj);
    }
    

    然后让所有AddMyExtension... 方法接受并返回IMyServiceCollection,调用更改为:

    builder.Services
        .WithMyObject(myObject)
        .AddMyExtension1()
        .AddMyExtension2()
        ...
        .AddMyExtensionN();
    

    或具有值元组的类似方法:

    public static class ServicesExts
    {  
        public static (IServiceCollection Collection, IMyObject Object) WithMyObject(this IServiceCollection services, IMyObject obj) 
            => (services, obj);
    }
    

    AddMyExtension... 有点像:

    public static (IServiceCollection Collection, object Object) AddMyExtension(this (IServiceCollection Collection, object Object) tuple)
    {
         // do the registrations ...
         return tuple;
    }
    

    用法看起来一样。

    【讨论】:

    • 感谢您的答复。我使用 myObject 创建所有依赖项的注册表。例如,我需要确保我的每个IRequest&lt;&gt; 类型都有一个IRequestHandler&lt;&gt; 实现。我将尝试第一种方法并让您知道。关于第二种方法,从我拥有的每个扩展中返回对象似乎是一种开销。所以,我可能不会继续这样做。再次感谢!
    • @ParthSekar 首先,值元组不是对象而是结构,其次,因为它用于一次性设置,所以您通常不应该关心。
    猜你喜欢
    • 2012-03-28
    • 2021-10-05
    • 1970-01-01
    • 2015-09-15
    • 1970-01-01
    • 2020-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多