Does Structuremap support Lazy out of the box?

前端 未结 2 1996
慢半拍i
慢半拍i 2021-01-11 17:58

Does structuremap allow you to do constructor injection in a lazy fashion? Meaning not creating the object which is injected until it is used?

2条回答
  •  -上瘾入骨i
    2021-01-11 18:49

    UPDATE: StructureMap v3 implements this out of the box, so this trick is no longer necessary.


    StructureMap version 2 doesn't, but with a few tricks you can get it to do what I believe you are looking for. First of all, you can already wire up Lazy instances manually like this:

    container = new Container(x =>
    {
        x.Scan(y =>
        {
            y.TheCallingAssembly();
            y.WithDefaultConventions();
        });
    
        x.For>().Use(y => new Lazy(y.GetInstance));
        x.For>().Use(y => new Lazy(y.GetInstance));
        x.For>().Use(y => new Lazy(y.GetInstance));
    });
    

    This works just fine, but you have to register each and every type individually. It would be nicer if you could take advantage of a more convention-based approach. Ideally, the following syntax would be nice.

    x.For(typeof(Lazy<>)).Use(typeof(Lazy<>));
    

    This syntax actually works... somewhat. Unfortunately, at runtime, StructureMap will attempt to find the "greediest" constructor for Lazy and settle on public Lazy(Func valueFactory, bool isThreadSafe). Since we didn't tell it what to do with the boolean isThreadSafe parameter, it will throw an exception when it tries to resolve `Lazy'.

    The documentation for Lazy states that the "thread safety mode" of the default Lazy(Func valueFactory) constructor is LazyThreadSafetyMode.ExecutionAndPublication, which just so happens to be what you get by passing true into the isThreadSafe parameter of the constructor above. So, if we could just tell StructureMap to pass true for isThreadSafe, we would get the same behavior as if we called the constructor we actually wanted to use in the first place (e.g. Lazy(Func valueFactory)).

    Simply registering x.For(typeof(bool)).Use(y => true) would be very reckless and dangerous since we would be telling StructureMap to go ahead and use the value true for any boolean anywhere. Instead, we need to tell StructureMap what value to use for just this one boolean parameter, which we can do like this.

    x.For(typeof(Lazy<>)).Use(typeof(Lazy<>))
     .CtorDependency("isThreadSafe").Is(true);
    

    StructureMap now knows to use the value of "true" for the isThreadSafe parameter when resolving Lazy. We can now use Lazy in constructor parameters, and get the behavior I believe you were looking for.

    You can read about the Lazy class in more detail here.

提交回复
热议问题