重新创建对象和 DI
Recreating an object and DI
我正在编写一个 class,它与 API 客户端对象一起工作,该对象有时会损坏,必须从使用它的对象内部重新创建。使用依赖注入执行此操作的最佳方法是什么?我对从 class 内部调用 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 类型的 class 中实现 IMyAPIClient 并重新创建它,从而绕过 DI 框架.我想知道这是否明智,或者是否有更好的方法来做到这一点?
我会首先尝试解决 ApiClient 的问题。对有缺陷的代码使用变通办法很少是一个好主意,但有时可能需要对第三方代码使用。如果问题出在第三方代码中,也可能建议将其放在单独的进程中,否则您无法知道失败是否会产生一些意想不到的副作用。
要创建新对象,我建议注入某种工厂。具体如何完成将取决于 DI/IoC 框架。最简单的可能是 Func<IMyAPIClient>
,但替代方案是显式工厂 -class。您可以选择工厂是否应该使用 IoC 容器来构造对象,或者直接构造它。此外,一些 IoC 框架将以某种特殊方式处理工厂,而其他框架可能要求工厂像其他任何东西一样进行注册。查看您的框架的文档,了解应如何管理工厂。
如果可能,我还建议将重启逻辑移至装饰器。这样它就与使用分离,并且在有多个用户或需要更新逻辑的情况下应该更加灵活。然而,注册装饰器可能有点棘手以确保它们正常工作,但这也取决于您的 IoC 框架。
我通过创建一个创建 IMyAPIClient 的工厂 class 解决了这个问题。
这样我就可以在这个工厂中处理依赖注入 class 而无需使其他代码依赖于 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++);
}
}
}
我正在编写一个 class,它与 API 客户端对象一起工作,该对象有时会损坏,必须从使用它的对象内部重新创建。使用依赖注入执行此操作的最佳方法是什么?我对从 class 内部调用 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 类型的 class 中实现 IMyAPIClient 并重新创建它,从而绕过 DI 框架.我想知道这是否明智,或者是否有更好的方法来做到这一点?
我会首先尝试解决 ApiClient 的问题。对有缺陷的代码使用变通办法很少是一个好主意,但有时可能需要对第三方代码使用。如果问题出在第三方代码中,也可能建议将其放在单独的进程中,否则您无法知道失败是否会产生一些意想不到的副作用。
要创建新对象,我建议注入某种工厂。具体如何完成将取决于 DI/IoC 框架。最简单的可能是 Func<IMyAPIClient>
,但替代方案是显式工厂 -class。您可以选择工厂是否应该使用 IoC 容器来构造对象,或者直接构造它。此外,一些 IoC 框架将以某种特殊方式处理工厂,而其他框架可能要求工厂像其他任何东西一样进行注册。查看您的框架的文档,了解应如何管理工厂。
如果可能,我还建议将重启逻辑移至装饰器。这样它就与使用分离,并且在有多个用户或需要更新逻辑的情况下应该更加灵活。然而,注册装饰器可能有点棘手以确保它们正常工作,但这也取决于您的 IoC 框架。
我通过创建一个创建 IMyAPIClient 的工厂 class 解决了这个问题。 这样我就可以在这个工厂中处理依赖注入 class 而无需使其他代码依赖于 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++);
}
}
}