Registering cascading dependencies (Take 2)

狂风中的少年 提交于 2019-12-11 07:47:45

问题


I attempted to ask this question yesterday and failed completely to make sense. So I've built a reproduction to demonstrate my problem.

In the following program I am resolving Bar witch should have a Foo and a Fool injected into it. Fool also has a Foo injected into it. The catch is I want Bar and Fool to both use the same Foo. In the following code that is not happening.

class Program
{
    static void Main(string[] args)
    {
        IUnityContainer container = new UnityContainer();

        Console.WriteLine("Resolving Bar");
        container.Resolve<Bar>();
        Console.ReadLine();
    }
}

public class Foo
{
    public Foo()
    {
        Console.WriteLine("Foo created " + this.GetHashCode());
    }
}

public class Fool
{
    public Foo Foo { get; set; }
    public Fool(Foo foo)
    {
        Foo = foo;
        Console.WriteLine("Fool created with injected Foo " + foo.GetHashCode());
    }
}
public class Bar
{
    public Bar(Foo foo, Fool fool)
    {
        Console.WriteLine("Bar created with injected Foo " + foo.GetHashCode());
        Console.WriteLine("Bar created with injected Fool.Foo " + fool.Foo.GetHashCode());
        // I want foo == fool.Foo
    }
}
public class Blat
{
    public Blat(Foo foo, Fool fool)
    {
        Console.WriteLine("Blat created with injected Foo " + foo.GetHashCode());
        Console.WriteLine("Blat created with injected Fool.Foo " + fool.Foo.GetHashCode());
    }
}

I could Resolve the types and define the a specific injection constructor in the Main method, but I have a complication. In this case I also create a Blat as well as a Bar. The catch is I want the Blat and the Bar to use different Foo's.

Consider:

   static void Main(string[] args)
    {
        IUnityContainer container = new UnityContainer();
        var foo = container.Resolve<Foo>();
        container.RegisterType<Fool>(new InjectionConstructor(foo));
        var fool = container.Resolve<Fool>();
        container.RegisterType<Bar>(new InjectionConstructor(foo, fool));
        container.RegisterType<Blat>(new InjectionConstructor(foo, fool));

        Console.WriteLine("Resolving Bar");
        container.Resolve<Bar>();
        container.Resolve<Blat>();
        Console.ReadLine();
    }
}

In this case Bar.Foo == Bar.Fool.Foo but Blat.Foo == Bar.Foo. In other words I want Bar.Foo == Bar.Fool.Foo && Blat.Foo != Bar.Foo

Is there a way to do this? I will be resolving many types of Bar's and Blat's so I would like to avoid creating child containers for each Bar, Blat, etc...

EDITTED TO FURTHER CONFUSE THE ISSUE

The problem is in the real world I have something like the following:

 BaseViewModel(Context context, ServiceA a, ServiceB b)

Each control will need a ViewModel created that uses a different context. In each viewModel the services have to use the same context. So I want Unity to create context, a, and b all using the same context.

I could do something similar to what you suggest. I could set a Context property on the services in the constructor of BaseViewModel, but that seems odd to me. Right now I'm just newing up the services in the constructor, but I'd rather do it with Unity so they aren't coupled so tightly. I was hoping there was a more elegant way.


回答1:


With your IUnityContainer, register Foo with a PerResolveLifetimeManager, i.e.:

static void Main(string[] args)
{
    IUnityContainer container = new UnityContainer();
    container.RegisterType<Foo>(new PerResolveLifetimeManager());

    Console.WriteLine("Resolving Bar");
    container.Resolve<Bar>();
    container.Resolve<Blat>();
    Console.ReadLine();
}

When you resolve Bar, the same instance of Foo will be injected into Bar and injected into Fool.

Then when you resolve Blat, a new instance of Foo will be injected into Blat and into Fool.

So Bar.Foo == Bar.Fool.Foo and Blat.Foo == Blat.Fool.Foo but Bar.Foo != Blat.Foo and Bar.Fool.Foo != Blat.Fool.Foo.

Every time you call container.Resolve, only one instance of Foo is ever resolved for that graph, that is what PerResolveLifetimeManager does.




回答2:


Have you ever considered something like this:

public class Bar
{
  public Bar(Fool fool)
  {
    this.Fool = fool;
  }
  public Foo Foo
  { 
    get { return this.Fool.Foo; }
    set { this.Fool.Foo = value; }
  }
  public Fool Fool { get; set; }
}

where Bar.Foo is just a convenience setter/getter for Bar.Fool.Foo? Why inject the same instance twice?



来源:https://stackoverflow.com/questions/9418718/registering-cascading-dependencies-take-2

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!