c# - 在应用依赖注入(inject)时,Func<in T, out TResult> 是否适合用作 ctor arg?

标签 c# dependency-injection delegates inversion-of-control func

例子:

public class BusinessTransactionFactory<T>  where T : IBusinessTransaction
{
    readonly Func<Type, IBusinessTransaction> _createTransaction;

    public BusinessTransactionFactory(Func<Type, IBusinessTransaction> createTransaction)
    {
        _createTransaction = createTransaction;
    }

    public T Create()
    {
        return (T)_createTransaction(typeof(T));
    }
}

使用相同的容器设置代码:

public class DependencyRegistration : Registry
{
    public DependencyRegistration()
    {
        Scan(x =>
        {
            x.AssembliesFromApplicationBaseDirectory();
            x.WithDefaultConventions();
            x.AddAllTypesOf(typeof(Repository<>));
            x.ConnectImplementationsToTypesClosing(typeof(IRepository<>));
        });

        Scan(x =>
        {
            x.AssembliesFromApplicationBaseDirectory();
            x.AddAllTypesOf<IBusinessTransaction>();
            For(typeof(BusinessTransactionFactory<>)).Use(typeof(BusinessTransactionFactory<>));
            For<Func<Type, IBusinessTransaction>>().Use(type => (IBusinessTransaction)ObjectFactory.GetInstance(type));
        });


        For<ObjectContext>().Use(() => new ManagementEntities());
    }
}

你怎么看?

最佳答案

力学

在机械层面上,使用委托(delegate)非常好,因为委托(delegate)基本上是一个 anonymous Role Interface。 .换句话说,无论您是注入(inject)委托(delegate)、接口(interface)还是抽象基类,都无关紧要。

概念

在概念层面上,牢记依赖注入(inject)的目的很重要。您使用 DI 的原因可能与我不同,但 IMO DI 的目的是提高代码库的可维护性

这个目标是否通过注入(inject)委托(delegate)而不是接口(interface)来实现是值得怀疑的。

委托(delegate)作为依赖项

第一个问题是委托(delegate)传达意图的程度。有时接口(interface)名称本身就传达了意图,而标准委托(delegate)类型几乎没有。

例如,type 在这里并不能传达太多意图:

public BusinessTransactionFactory(Func<Type, IBusinessTransaction> createTranscation)

幸运的是,createTranscation名称仍然暗示委托(delegate)所扮演的角色,但只要考虑(为了论证的缘故)如果作者不那么小心,构造函数的可读性如何:

public BusinessTransactionFactory(Func<Type, IBusinessTransaction> func)

换句话说,使用委托(delegate)将焦点从类型名称转移到参数名称。这不一定是个问题 - 我只是指出您需要注意这种转变。

可发现性与可组合性

另一个问题是涉及实现依赖项的类型时的可发现性与可组合性。例如,这两个实现 public Func<Type, IBusinessTransaction> :

t => new MyBusinessTransaction()

public class MyBusinessTransactionFactory
{
    public IBusinessTransaction Create(Type t)
    {
        return new MyBusinessTransaction();
    }
}

但是,在类的情况下,具体的非虚拟 Create 几乎是偶然的方法匹配所需的委托(delegate)。 它非常可组合,但不太容易被发现

另一方面,当我们使用接口(interface)时,类在实现接口(interface)时成为is-a关系的一部分,因此通常更容易找到所有实现者并相应地分组和组合它们。

请注意,这不仅适用于程序员阅读代码,也适用于 DI 容器。因此,当您使用接口(interface)时,可以更轻松地实现约定优于配置

1:1 接口(interface)与 RAP

有些人已经注意到,当尝试使用 DI 时,他们最终会得到很多 1:1 接口(interface)(例如 IFoo 和相应的 Foo 类)。在这些情况下,接口(interface) ( IFoo ) 似乎是多余的,并且似乎很想摆脱接口(interface)并改用委托(delegate)。

然而,many 1:1 interfaces are really a symptom of a violation of the Reused Abstractions Principle .当您重构代码库以在多个地方重用相同的抽象时,将该抽象的角色显式建模为接口(interface)(或抽象基类)是有意义的。

结论

界面不仅仅是机械。它们在应用程序代码库中明确地建模角色。中心角色应该由接口(interface)来表示,而一次性工厂及其类似物可以作为委托(delegate)来使用和实现。

关于c# - 在应用依赖注入(inject)时,Func<in T, out TResult> 是否适合用作 ctor arg?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8285880/

相关文章:

c# - 显示 SelectedItem 的属性

c# - 水平滚动在 MAUI 中不起作用。我错过了什么还是这是一个错误?

swift - 有没有比这更好的方法在 Swift 中进行依赖注入(inject)?

c# - 需要解释事件处理和委托(delegate)

c# - C#中变量名中@字符的用途/含义是什么?

c# - WCF:如何阻止 myServiceHost.Close() 处理 myServiceHost 对象?

c# - 将 Ninject 与 ServiceLocater 模式结合使用——好还是坏

.net - asp.net core 2.1 中的共享资源本地化和简单注入(inject)器

swift - 委托(delegate)(创建 sideMenu 时,委托(delegate)?返回 nil)

objective-c - 我将如何实现委托(delegate)将值从子 swift 类传递到父 Objective-C 类?