注入依赖作为方法参数而不是构造函数参数

Sat*_*jit 6 c# dependency-injection mef autofac

我们可以使用 MEF 或 Autofac 将依赖项作为方法参数而不是构造函数参数注入吗?

谢谢

Joh*_*ger 3

I don't know about MEF, as I've never used it. You can do it with Unity and with Autofac

Unity

From the MSFT documentation.

Unity instantiates dependent objects defined in parameters of methods that carry the InjectionMethod attribute within the scope of the target object. Then it calls the attributed method of the target object before returning the object to the caller. You must apply the InjectionMethod attribute in the target class to initiate method call injection.

public class MyObject
{
   public SomeOtherObject dependentObject;

  [InjectionMethod]
  public void Initialize(SomeOtherObject dep) 
  {
    // assign the dependent object to a class-level variable
    dependentObject = dep;
  }
}
Run Code Online (Sandbox Code Playgroud)

That will mark the class as having a dependency method that must get invoked when the class is instanced, and have its method parameter injected.

IUnityContainer uContainer = new UnityContainer();
MyObject myInstance = uContainer.Resolve<MyObject>();

// access the dependent object
myInstance.dependentObject.SomeProperty = "Some value";
Run Code Online (Sandbox Code Playgroud)

Autofac

Autofac does it through lambdas or callbacks during the activation of a service. From the Autofac documentation

While constructor parameter injection is the preferred method of passing values to a component being constructed, you can also use property or method injection to provide values.

Property injection uses writeable properties rather than constructor parameters to perform injection. Method injection sets dependencies by calling a method.

// Register the type that you want to resolve with a resolution callback. Within the callback, invoke the method with a resolved dependency.
builder.Register(c => {
  var result = new MyObjectType();
  var dep = c.Resolve<TheDependency>();
  result.SetTheDependency(dep);
  return result;
});
Run Code Online (Sandbox Code Playgroud)

An alternative is the registration callback.

builder
  .Register<MyObjectType>()
  .OnActivating(e => {
      var dep = e.Context.Resolve<TheDependency>();
      e.Instance.SetTheDependency(dep);
  });
Run Code Online (Sandbox Code Playgroud)

Both frameworks can only do the method injection at the time of resolution. However, you can't inject a dependency in to a method after the object has been instanced. In those scenarios, you should use a factory to fetch the dependency you have, having the factory resolve it through your DI container.

Factory

// Create the factory. The factory will have a static method that the DI system can register a lambda with, so that the factory can resolve through the DI container without being tightly coupled to it.
public class BarFactory
{
    private static Func<IBarDependency> internalFactory;

    public static void SetFactory(Func<IBarDependency> factory)
    {
        this.internalFactory = factory;
    }

    public IBarDependency CreateBar()
    {
        // Use the DI container lambda assigned in SetFactory to resolve the dependency.
        return internalFactory();
    }
}

public class DependencyInjectionBootstrap
{
    IContainer container;

    public void SetupDI()
    {
        var builder = new ContainerBuilder();
        builder.RegisterType<BarDependency>().As<IBarDependency>();
        container = builder.Build();

        // Tell the factory to resolve all IBarDependencies through our IContainer.
        BarFactory.SetFactory(() => container.Resolve<IBarDependency>());
    }
}

public class FooViewModel
{
    public void ExecuteSave()
    {
        var barFactory = new BarFactory();
        IBarDependency bar = barFactory.CreateBar();
    }
}
Run Code Online (Sandbox Code Playgroud)