有没有一种简单的方法来注册Castle Windsor的静态封闭?

nin*_*eff 6 .net closures dependency-injection castle-windsor ioc-container

我一直在尝试使用命名委托而不是单方法接口.这对代码的大小一定的优势,因为我们可以从(一些换行符删除,以免夸大的情况下)去:

public interface IProductSource
{
    IEnumerable<Product> GetProducts();
}
public class DataContextProductSource : IProductSource
{
    private readonly DataContext _DataContext;
    public DataContextProductSource(DataContext dataContext)
    {
        if (dataContext == null) throw new ArgumentNullException("dataContext");
        _DataContext = dataContext;
    }
    public IEnumerable<Product> GetProducts()
    {
        return _DataContext.Products.AsEnumerable();
    }
}
Run Code Online (Sandbox Code Playgroud)

至:

public delegate IEnumerable<Product> DGetProducts();
public static class DataContextFunctions
{
    public DGetProducts GetProducts(DataContext dataContext)
    {
        if (dataContext == null) throw new ArgumentNullException("dataContext");
        return () => dataContext.Products.AsEnumerable();
    }
}
Run Code Online (Sandbox Code Playgroud)

这基本上利用了这样一个事实:一旦你使用依赖注入足够远,很多类变得只是闭包.这些类可以用返回lambdas的函数替换.整套相关函数(不需要封装任何可变状态,但在"标准"依赖注入中使用类表示)可以汇总到静态类(或VB术语中的"模块") .

这一切都很好,但我找不到使用Castle Windsor注册这些静态方法的最佳方法.没有依赖关系的方法很简单:

Component.For<DGetIntegers>().Instance(Integers.GetOneToTen)
Run Code Online (Sandbox Code Playgroud)

但是我们上面的DataContextFunctions.GetProducts有一些依赖关系.我发现注册这个的最好方法是:

Component.For<DGetProducts>().UsingFactoryMethod(
    kernel => DataContextFunctions.GetProducts(kernel.Resolve<DataContext>())
Run Code Online (Sandbox Code Playgroud)

这可能会变得非常冗长,显然不得不直接询问内核的每一个依赖类型.在我看来,容器应该需要的所有静态信息都是可用的,因此应该可以这样做.

问题是,Castle Windsor(或任何其他容器)是否有一种简单的方法可以做到这一点,我已经错过了,或者是否存在技术问题,或者它是否只是包含在一个用例中?

Mar*_*ann 10

简短的回答

你试图让DI容器(Castle Windsor)执行功能组合,但它实际上是针对对象组合的.这只会给你带来很多摩擦.我的猜测是你将获得与其他容器相同的体验.

DI容器是围绕面向对象的概念设计的 - 特别是SOLID.它们与这些原理配合得非常好,因为它们的设计具有构造函数注入和自动布线等内在的理解.

更实用的方法没有任何问题,但我还没有看到围绕功能组合而不是对象组合构建的DI容器.

答案很长

由于几个原因,使用委托作为DI的一般原则往往在静态类型语言(至少在.NET中)中存在问题.从概念上讲,这种方法没有任何问题,因为委托可以被视为匿名角色接口.但是,由于类型模糊,它往往变得笨拙.

我通常看到的最常见的方法是使用BCL的内置代理,例如Func<T>,Action<T>等等.但是,您可能有许多不同的消费者依赖Func<string>于哪种情况变得模棱两可 - 仅仅因为消费者需要一个Func<string>并不意味着他们需要代理人担任同一个角色.虽然机械上可能会将DI与代理一起使用,但会发生的情况是委托隐藏应用程序角色.角色消失,只剩下机械师.

然后,您可以按照OP中的建议为每个角色定义自定义委托,如此委托所建议的那样:

public delegate IEnumerable<Product> DGetProducts();
Run Code Online (Sandbox Code Playgroud)

但是,如果你采取这种方式,那么什么都得不到.仍必须为每个角色定义"角色委托".相比之下,定义一个类似的界面,应该清楚,唯一的保存是几个尖括号和一个显式的方法定义:

public interface IProductSource { IEnumerable<Product> GetProducts(); }
Run Code Online (Sandbox Code Playgroud)

这不是很多开销(如果有的话).

您可能还想看一下这个讨论:http://thorstenlorenz.wordpress.com/2011/07/23/dependency-injection-is-dead-long-live-verbs/


Krz*_*mic 4

这是一个有趣的方法。我认为您可以使用自定义激活器轻松完成此工作。