例子:
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/