c# - 未注册类型的 SimpleInjector 强制 Lifestyle.Transient

标签 c# inversion-of-control simple-injector

我有一个包装类如下:

// this is not used for IoC purposes, but by code to cast object to known T
internal interface ITaskCompletionSourceWrapper
{
    void SetResult(object result);
    /* snip */
}

internal class TaskCompletionSourceGenericWrapper<TResult> : ITaskCompletionSourceWrapper
{
    readonly TaskCompletionSource<TResult> tcs;
    public TaskCompletionSourceGenericWrapper() =>        
        this.tcs = new TaskCompletionSource<TResult>(TaskCreationOptions.RunContinuationsAsynchronously);
    public void SetResult(object result) => tcs.SetResult((TResult)result);
    /* snip */
}

我目前使用 Activator 实例化的地方:
var responseType = request
                     .GetType()
                     .GetInterfaces()
                     .FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IRequest<>))
                     GetGenericArguments()[0];

var wrapperType = typeof(TaskCompletionSourceGenericWrapper<>).MakeGenericType(responseType);
var tcsWrapper = this.container.GetInstance(wrapperType) as ITaskCompletionSourceWrapper;

我将其切换到 SimpleInjector(可能使用日志记录和其他 IOC 优点)并认为一切都很好,直到我发现一个问题(这是由于共享生活方式):
/* snip responseType code from above */
var wrapperType = typeof(TaskCompletionSourceGenericWrapper<>).MakeGenericType(responseType);
var tcsWrapper = this.container.GetInstance(wrapperType) as ITaskCompletionSourceWrapper;

// i can see the type has been registered as scoped, but we need it to be unique
[30] = ServiceType = TaskCompletionSourceGenericWrapper<Object>, Lifestyle = Async Scoped

以上是在 AsyncScopedLifestyle.BeginScope 中调用的。堵塞。

我想在运行时使用 SimpleInjector 实例化这个包装器(但要确保 Lifestyle.Transient ):

包装器的类型在 int 中几乎是任意的。 , string , bool等等,但也可以是简单的 POCO 类。

这类似于开放通用注册的情况,但我宁愿避免让其他开发人员为简单类型指定程序集(因为他们肯定会忘记,而且他们的类无论如何都很简单——命令/查询 POCO 等)。

请问我怎样才能达到上述目的,还是我被迫注册收藏?

或者这是否与生活方式不匹配更深 - 我希望不会,因为包装器没有依赖项(也许除了 ILogger 之外不会)只是做一些简单类的实例化(我想替换 Activator 而不是解耦组件 IoC 样式) .

最佳答案

基于他们的文档 Batch-Registration / Auto-Registration和经验,使用依赖注入(inject)时需要注册接口(interface)的实现。

var container = new Container();
// If related classes exist in a different assembly then add them here
var assemblies = new[] { typeof(TaskCompletionSourceGenericWrapper<>).Assembly };

container.Collection.Register(typeof(TaskCompletionSourceGenericWrapper<>), assemblies, Lifestyle.Transient);

DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));

我能想到但尚未测试的一种技巧是创建一个包装器类,该类返回一个深拷贝,即包装器的克隆。返回对象的克隆类似于 transient ,因为它每次请求它时都会返回一个新实例,但这种方法的缺点是您只能对可序列化的类执行此操作,因此您可能需要添加 [Serializable()] .引用 Deep cloning objects了解更多信息。
public interface IUglyDuckling
{
    ITaskCompletionSourceWrapper GetITaskCompletionSourceWrapper(Type type);
}
public class UglyDuckling : IUglyDuckling
{
    public ITaskCompletionSourceWrapper GetITaskCompletionSourceWrapper(Type type)
    {
        var wrapperType = typeof(TaskCompletionSourceGenericWrapper<>).MakeGenericType(type);
        var tcsWrapper = this.container.GetInstance(wrapperType) as ITaskCompletionSourceWrapper;
        return ObjectCopier.Clone<ITaskCompletionSourceWrapper>(tcsWrapper);
    }
}

关于c# - 未注册类型的 SimpleInjector 强制 Lifestyle.Transient,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61991252/

相关文章:

java - 当子类未实现所有构造函数时实例化基类

c# - Automapper 使用简单注入(inject)器 (Ioc) 将依赖项注入(inject)自定义类型转换器

c# - 通用注入(inject)工厂

c# - 在单元测试中使用 DI 容器

c# - 简单注入(inject)器 - 注入(inject)容器属性

c# - 处理 null 的 Linq 表达式

c# - 编写包含子目录的目录列表<String>

c# - 如何在没有 com 库的情况下读写二进制 excel 文件

c# - .NET 内置 AVL 树?

nhibernate - 如何停止 Fluently.Configure 自动连接