【问题标题】:Recreating an object and DI重新创建对象和 DI
【发布时间】:2021-08-29 22:39:49
【问题描述】:

我正在编写一个与 API 客户端对象一起使用的类,该对象有时会损坏并且必须从使用它的对象内部重新创建。使用依赖注入的最佳方法是什么?我对从类内部调用 DI 框架犹豫不决,因为它使我的代码依赖于它。

public class MyObject
{
    protected IMyAPIClient Client { get; set; }

    public MyObject(IMyAPIClient client)
    {
        Client = client;
    }

    protected async Task<ReturnType> Run<ReturnType>(Func<Task<ReturnType>> action, int attempt = 1)
    {
        try
        {
            return await action();
        }
        catch(Exception exception)
        {
            Client = await GetNewClient();
            if(attempt > MAX_ATTEMPTS)
            {
                throw new Exception($"Failed {attempt} times", exception);
            }
            
            return await Run(action, attempt++);
        }
    }

    protected async Task<IMyAPIClient> GetNewClient()
    {
        // what to do here?
    }
}

我想出的一个解决方案是在一个知道 IMyAPIClient 类型的类中实现 IMyAPIClient 并重新创建它,从而绕过 DI 框架。我想知道这是否明智,或者是否有更好的方法?

【问题讨论】:

  • 如果您的 IMyAPIClient 实例不稳定,我会尝试修复它。如果你改写你的问题并添加导致问题的代码,也许这里有人可以找到真正的问题。 BR
  • 您使用的是什么 IoC 框架?例如,如果您使用 Autofac,这很容易 - 只需注入一个 func。
  • 通常最好找出问题的原因而不是更换它。否则我们永远学不会

标签: c# design-patterns dependency-injection


【解决方案1】:

我会首先尝试解决 ApiClient 的问题。对有缺陷的代码使用变通办法很少是一个好主意,但有时可能需要第三方代码。如果问题出在第三方代码中,也可能建议将其放在单独的进程中,否则您无法知道失败是否有一些意想不到的副作用。

要创建新对象,我建议注入某种工厂。具体如何完成将取决于 DI/IoC 框架。最简单的可能是Func&lt;IMyAPIClient&gt;,但另一种选择是显式工厂类。您可以选择工厂是应该使用 IoC 容器来构造对象,还是直接构造它。此外,一些 IoC 框架会以某种特殊的方式处理工厂,而另一些框架可能需要像其他所有东西一样注册工厂。查看您的框架的文档,了解应如何管理工厂。

如果可能,我还建议将重启逻辑移至装饰器。这样就和使用分离了,在有多个用户或者需要更新逻辑的情况下应该更加灵活。但是,注册装饰器可能有点棘手,以确保它们正常工作,但这也取决于您的 IoC 框架。

【讨论】:

    【解决方案2】:

    我通过创建一个创建 IMyAPIClient 的工厂类解决了这个问题。 这样我就可以在这个工厂类中处理依赖注入,而无需让其他代码依赖于 DI 框架。

    public class MyObject
    {
        protected IMyAPIClientFactory ClientFactory { get; set; }
    
        public MyObject(IMyAPIClientFactory clientFactory)
        {
            ClientFactory = clientFactory;
            Client = clientFactory.CreateClient();
        }
    
        protected async Task<ReturnType> Run<ReturnType>(Func<Task<ReturnType>> action, int attempt = 1)
        {
            try
            {
                return await action();
            }
            catch(Exception exception)
            {
                Client = await clientFactory.CreateClient();
                if(attempt > MAX_ATTEMPTS)
                {
                    throw new Exception($"Failed {attempt} times", exception);
                }
                
                return await Run(action, attempt++);
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-06
      • 2018-05-25
      • 1970-01-01
      相关资源
      最近更新 更多