构造函数注入通过反射解决的循环依赖关系?

时间:2011-12-02 14:39:36

标签: c# reflection dependency-injection

在这里回答我的问题是关于循环依赖的一半:

C# ASP.NET Dependency Injection with IoC Container Complications

演示者依赖于IView。 Page(实现IView)取决于演示者。其他已经解决了从构造函数注入到属性注入的转换

我不喜欢这样,因为我觉得你现在需要制作可以在外部修改的公共属性,并且也成为开发人员初始化的责任。

但似乎我能够以另一种方式解决这个问题。

通过具有默认构造函数的页面以及重载的参数化构造函数,您可以通过反射调用无参数构造函数来创建对象 然后通过注入依赖项来调用重载的。

我举例说明:

class TestObject
{
    public string Name { get; set; }

    public TestObject()
    {
       Name = "Constructed with no args";
       Console.WriteLine("constructor hash code: " + GetHashCode());
    }

    public TestObject(string name)
    {
        this.Name = name;
        Console.WriteLine("constructor hash code: " + GetHashCode());
    }
}

这个对象可以简单地构建:

var obj = Activator.CreateInstance<TestObject>();

var obj = new TestObject();

但是我可以通过反射使用重载的构造函数来注入依赖项:

ConstructorInfo ctor = obj.GetType().GetConstructors()[1];
ctor.Invoke(obj, new[] { "injected" });

我能够使用这种方法连接structmap以在创建后注册实例,然后注入依赖项。

当然我们可以使用常规方法来注入依赖项,但这会再次打破封装,所以你可以调用它 再次覆盖依赖关系。

同样作为构造函数,只能通过静态代码访问它。

但我不知道我对此感觉如何,感觉有点像黑客或其他我可以在C#中偶然发生的事情。

我想听听你的想法

感谢。

1 个答案:

答案 0 :(得分:1)

我不喜欢这种反射的使用,因为这意味着你不能轻易地创建一个没有IoC容器的视图/演示者。

解决IoC容器需求的一种方法是使用工厂轻松创建视图/演示者并将反射逻辑放在工厂中。

但是,此时您可以使用简单的属性或Initialize(view) / Initialize(presenter)方法。调用这些方法的责任由工厂或IoC容器(作为工厂)从开发人员那里拿走。

在构造时将依赖项传递给对象的替代方法是传递可以为对象构建依赖项的工厂。最简单的工厂形式是简单的Func

void Main()
{
    var controller = Controller.Create (c => new View (c));  
}

class Controller {
    private View view;

    // This could also be a constructor, but I prefer to think of this
    // as a factory method.
    public static Controller Create (Func<Controller, View> viewBuilder) {
        var controller = new Controller ();
        var view = viewBuilder (controller);
        controller.Initialize (view);
        return controller;
    }

    protected Controller() {
    }

    protected void Initialize (View view) {
        this.view = view;
    }
}

class View {
    private Controller controller;

    public View (Controller controller) {
        this.controller = controller;
    }
}

如果你坚持使用一对构造函数,我会使无参数构造函数受到保护,除非在没有演示者/视图的情况下创建视图/演示者真的有效。这会阻止某人错误地使用该构造函数,因为在构造之后没有反射来初始化视图/展示器。

虽然我认为这在反思上稍微好一点,但是要创建一个受保护的无参数构造函数,以及一个受保护的初始化方法。

public class TestObject
{
    protected TestObject () {
    }

    public TestObject (string name) {
        Initialize (name)
    }

    protected Initialize (string name) {}
}

除非您使用反射,否则强制您无法在没有名称的情况下构造它。反射将被封装在工厂中,以确保Initialize也被调用。