使用构造函数

使用“表达式”指定构造函数

示例 :Made.Of 利用表达式指定构造函数

  • 使用 Register 方法注册类型时,通过 “表达式”指定构造函数,在 Resolve 对象时,容器将使用该指定的构造函数创建对象
  • Made.Of 方法利用“表达式”指定构造函数,其中参数部分可通过 Arg.Of 方法指定 ```csharp public interface IDependency { } public class Dep : IDependency {} public class Foo { public IDependency Dep { get; } public Foo(IDependency dep) => Dep = dep; }

class Register_strongly_typed_service_with_expression { [Test] public void Example() { var c = new Container(); c.Register();

  1. // 使用 Make.Of 方法,通过“表达式”指定构造函数
  2. // 使用 Arg.Of 方法,通过“表达式“指定构造函数的参数类型
  3. // new Foo(Arg.Of<IDependency>()) 并不会执行创建对象,仅作为“表达式”
  4. c.Register<Foo>(made: Made.Of(() => new Foo(Arg.Of<IDependency>())));
  5. Assert.IsNotNull(c.Resolve<Foo>());
  6. }

}

  1. **Made.Of 源码:**
  2. - serviceReturningExpr 参数类型为 **System.Linq.Expressions.Expression<Func<TService>>**,表明该参数是一个linq表达式,并非用于真实执行的委托代码。
  3. - argValues 参数类型为 **params Func<Request, object>[]**,用于为依赖提供参数值(可选)。
  4. - TypeMade 方法其本质是通过 **FromExpression **方法解构表达式。
  5. ```csharp
  6. public static TypedMade<TService> Of<TService>(
  7. System.Linq.Expressions.Expression<Func<TService>> serviceReturningExpr,
  8. params Func<Request, object>[] argValues) =>
  9. FromExpression<TService>(member => _ => DryIoc.FactoryMethod.Of(member), serviceReturningExpr, argValues);


FromExpression 源码:(Linq 相关的知识)**

  1. private static TypedMade<TService> FromExpression<TService>(
  2. Func<MemberInfo, FactoryMethodSelector> getFactoryMethodSelector,
  3. System.Linq.Expressions.LambdaExpression serviceReturningExpr, params Func<Request, object>[] argValues)
  4. {
  5. var callExpr = serviceReturningExpr.ThrowIfNull().Body;
  6. if (callExpr.NodeType == System.Linq.Expressions.ExpressionType.Convert) // proceed without Cast expression.
  7. return FromExpression<TService>(getFactoryMethodSelector,
  8. System.Linq.Expressions.Expression.Lambda(((System.Linq.Expressions.UnaryExpression)callExpr).Operand,
  9. Empty<System.Linq.Expressions.ParameterExpression>()),
  10. argValues);
  11. MemberInfo ctorOrMethodOrMember;
  12. IList<System.Linq.Expressions.Expression> argExprs = null;
  13. IList<System.Linq.Expressions.MemberBinding> memberBindingExprs = null;
  14. ParameterInfo[] parameters = null;
  15. if (callExpr.NodeType == System.Linq.Expressions.ExpressionType.New ||
  16. callExpr.NodeType == System.Linq.Expressions.ExpressionType.MemberInit)
  17. {
  18. var newExpr = callExpr as System.Linq.Expressions.NewExpression ?? ((System.Linq.Expressions.MemberInitExpression)callExpr).NewExpression;
  19. ctorOrMethodOrMember = newExpr.Constructor;
  20. parameters = newExpr.Constructor.GetParameters();
  21. argExprs = newExpr.Arguments;
  22. if (callExpr is System.Linq.Expressions.MemberInitExpression)
  23. memberBindingExprs = ((System.Linq.Expressions.MemberInitExpression)callExpr).Bindings;
  24. }
  25. else if (callExpr.NodeType == System.Linq.Expressions.ExpressionType.Call)
  26. {
  27. var methodCallExpr = (System.Linq.Expressions.MethodCallExpression)callExpr;
  28. ctorOrMethodOrMember = methodCallExpr.Method;
  29. parameters = methodCallExpr.Method.GetParameters();
  30. argExprs = methodCallExpr.Arguments;
  31. }
  32. else if (callExpr.NodeType == ExprType.Invoke)
  33. {
  34. var invokeExpr = (System.Linq.Expressions.InvocationExpression)callExpr;
  35. var invokedDelegateExpr = invokeExpr.Expression;
  36. var invokeMethod = invokedDelegateExpr.Type.GetTypeInfo().GetDeclaredMethod(nameof(Action.Invoke));
  37. ctorOrMethodOrMember = invokeMethod;
  38. parameters = invokeMethod.GetParameters();
  39. argExprs = invokeExpr.Arguments;
  40. }
  41. else if (callExpr.NodeType == System.Linq.Expressions.ExpressionType.MemberAccess)
  42. {
  43. var member = ((System.Linq.Expressions.MemberExpression)callExpr).Member;
  44. Throw.If(!(member is PropertyInfo) && !(member is FieldInfo),
  45. Error.UnexpectedFactoryMemberExpressionInMadeOf, member, serviceReturningExpr);
  46. ctorOrMethodOrMember = member;
  47. }
  48. else return Throw.For<TypedMade<TService>>(Error.NotSupportedMadeOfExpression, callExpr);
  49. var hasCustomValue = false;
  50. var parameterSelector = parameters.IsNullOrEmpty() ? null
  51. : ComposeParameterSelectorFromArgs(ref hasCustomValue,
  52. serviceReturningExpr, parameters, argExprs, argValues);
  53. var propertiesAndFieldsSelector =
  54. memberBindingExprs == null || memberBindingExprs.Count == 0 ? null
  55. : ComposePropertiesAndFieldsSelector(ref hasCustomValue,
  56. serviceReturningExpr, memberBindingExprs, argValues);
  57. return new TypedMade<TService>(getFactoryMethodSelector(ctorOrMethodOrMember),
  58. parameterSelector, propertiesAndFieldsSelector, hasCustomValue);
  59. }

使用“反射”指定构造函数

示例 :Made.Of 使用“反射”指定构造函数

  • 使用 Register 方法注册类型时,通过 Type 类的 GetConstructor 方法 指定构造函数,在 Resolve 对象时,使用该构造函数创建对象。

    1. class Register_with_reflection
    2. {
    3. [Test]
    4. public void Example()
    5. {
    6. var c = new Container();
    7. c.Register<IDependency, Dep>();
    8. // 使用 Type 类型的 GetConstructor 方法返回指定的构造函数
    9. c.Register<Foo>(made: Made.Of(typeof(Foo).GetConstructor(new[] { typeof(IDependency) })));
    10. Assert.IsNotNull(c.Resolve<Foo>());
    11. }
    12. }

注意:当注册泛型类型时仅能使用以下这种方法

示例 :Made.Of 使用“反射”为泛型类型指定构造函数

  1. public interface IDependency<T> { }
  2. public class Foo<T>
  3. {
  4. public IDependency<T> Dep { get; }
  5. public Foo(IDependency<T> dep) => Dep = dep;
  6. }
  7. public class Dep<T> : IDependency<T> {}
  8. class Register_open_generics_with_reflection
  9. {
  10. [Test]
  11. public void Example()
  12. {
  13. var c = new Container();
  14. c.Register<IDependency<int>, Dep<int>>();
  15. // 通过 Type 类的 GetConstructors 方法,获取第一个构造函数
  16. c.Register(typeof(Foo<>), made: Made.Of(typeof(Foo<>).GetConstructors()[0]));
  17. Assert.IsNotNull(c.Resolve<Foo<int>>());
  18. }
  19. }

根据方法参数选择用于解析的构造函数

DryIoc 支持根据解析的参数来选择合适的构造函数。先从参数数量最大的构造函数开始匹配,若无法正确解析参数,则选择下一个参数更少的构造函数,以此类推。若最终无法取得构造函数,则抛出异常。

示例 :FactoryMethod.ConstructorWithResolvableArguments 参数

根据可解析的参数查找构造函数,若查找失败则抛出异常。

  • 使用 Register 方法,为指定“服务类”设置 FactoryMethod.ConstructorWithResolvableArguments。(即无需指定构造函数)

    1. class Register_with_automatic_constructor_selection
    2. {
    3. [Test]
    4. public void Example()
    5. {
    6. var c = new Container();
    7. c.Register<IDependency, Dep>();
    8. c.Register<Foo>(made: FactoryMethod.ConstructorWithResolvableArguments);
    9. Assert.IsNotNull(c.Resolve<Foo>());
    10. }
    11. }
  • 使用 rules.With 方法,为 container 所有“服务类”设置 FactoryMethod.ConstructorWithResolvableArguments。(即无需指定构造函数)

    1. class Register_with_automatic_constructor_selection_for_entire_container
    2. {
    3. [Test]
    4. public void Example()
    5. {
    6. var c = new Container(rules => rules.With(FactoryMethod.ConstructorWithResolvableArguments));
    7. c.Register<IDependency, Dep>();
    8. c.Register<Foo>(); // no need to specify how to select constructor
    9. Assert.IsNotNull(c.Resolve<Foo>());
    10. }
    11. }

    DryIoc 源码:

  • FactoryMethod.ConstructorWithResolvableArguments 属性返回的 FactoryMethodSelector 类型。

  • FactoryMethodSelector 类型支持隐式转换为 Made 类型。 ```csharp public sealed class FactoryMethod { public static readonly FactoryMethodSelector ConstructorWithResolvableArguments; //… }

public class Made { public static implicit operator Made(FactoryMethodSelector factoryMethod); //… }

  1. <a name="1heY8"></a>
  2. # 使用工厂方法(代替构造函数)
  3. > DryIoc directly supports static or instance factory methods. Container will inject dependencies into method parameters the same way as for constructors.
  4. > DryIcom 原生支持静态的或实例的工厂方法。容器采用类似注入构造函数参数的方式为工厂方法注入参数。
  5. <a name="uO4Kg"></a>
  6. ## 静态工厂方法
  7. <a name="ZTqvd"></a>
  8. #### 示例 :Made.Of 方法 指定静态工厂函数
  9. - 使用 Register 方法注册类型时,将某静态方法指定工厂方法,在 Resolve 对象时,使用该工厂方法创建对象
  10. ```csharp
  11. public interface IFoo {}
  12. public class FooBar : IFoo {}
  13. public class Repo
  14. {
  15. public void Add(IFoo foo) {}
  16. }
  17. public static class FooFactory
  18. {
  19. public static IFoo CreateFoo(Repo repo)
  20. {
  21. var foo = new FooBar();
  22. repo.Add(foo);
  23. return foo;
  24. }
  25. }
  26. var c = new Container();
  27. c.Register<Repo>();
  28. // 使用工厂静态方法作FooFactory.CreateFoo,该代码并不执行创建对象,仅作为“表达式”
  29. c.Register<IFoo>(made: Made.Of(() => FooFactory.CreateFoo(Arg.Of<Repo>())));

实例工厂方法

示例 :Made.Of 方法 指定静态工厂函数

  • 为 IFooFactory 接口注册 FooFactory 类。
  • 通过 ServiceInfo.Of 方法指定工厂类的“服务类”,DryIoc 将根据该类型(IFooFactory),解析出工厂方法实例 (FooFactory),然后调用该实例的工厂方法(CreateFoo)。 ```csharp public interface IDependency { } public class Dep : IDependency { }

public interface IFoo {} public class FooBar : IFoo {} public class Repo { public void Add(IFoo foo) {} }

public interface IFooFactory { IFoo CreateFoo(Repo repo); } public class FooFactory : IFooFactory { public FooFactory(IDependency dep) { }

  1. public IFoo CreateFoo(Repo repo)
  2. {
  3. var foo = new FooBar();
  4. repo.Add(foo);
  5. return foo;
  6. }

}

var c = new Container(); // 为 IFooFactory 注册 FooFactory c.Register(Reuse.Singleton); c.Register(); c.Register(); c.Register(made: Made.Of(r => ServiceInfo.Of(), f => f.CreateFoo(Arg.Of()))); Assert.IsNotNull(c.Resolve());

  1. <a name="e0ppt"></a>
  2. #### 疑问 :如果“服务类”(IFooFactory)注册多个“实现类”,此时运行程序将会如何?
  3. - 新增 FooFactoryOther 类继承自 IFooFactory 接口,同时在 container 中注册该类型为单例模式
  4. ```csharp
  5. // 新增一个“实现类”
  6. public class FooFactoryOther : IFooFactory
  7. {
  8. public FooFactoryOther(IDependency dep) { }
  9. public IFoo CreateFoo(Repo repo)
  10. {
  11. var foo = new FooBar();
  12. repo.Add(foo);
  13. return foo;
  14. }
  15. }
  16. var c = new Container();
  17. c.Register<IFooFactory, FooFactory>(Reuse.Singleton);
  18. c.Register<IFooFactory, FooFactoryOther>(Reuse.Singleton);
  19. c.Register<IDependency, Dep>();
  20. c.Register<Repo>();
  21. c.Register<IFoo>(made: Made.Of(r => ServiceInfo.Of<IFooFactory>(), f => f.CreateFoo(Arg.Of<Repo>())));
  22. Assert.IsNotNull(c.Resolve<IFoo>());

异常信息 :
DryIoc.ContainerException:“code: Error.ExpectedSingleDefaultFactory;
message: Expecting a single default registration but found many:
(DefaultKey(0), {FactoryID=144, ImplType=ConsoleApp1.FooFactory, Reuse=Singleton {Lifespan=1000}}),
(DefaultKey(1), {FactoryID=145, ImplType=ConsoleApp1.FooFactoryOther, Reuse=Singleton {Lifespan=1000}})
when resolving ConsoleApp1.IFooFactory
in resolution root ConsoleApp1.IFoo FactoryId=148
from container without scope.
Please identify service with key, or metadata, or use Rules.WithFactorySelector to specify single registered factory.”

无法查找到预期的唯一的注册信息,但能查找到多个注册信息:
(DefaultKey(0), {FactoryID=144, ImplType=ConsoleApp1.FooFactory, Reuse=Singleton {Lifespan=1000}}),
(DefaultKey(1), {FactoryID=145, ImplType=ConsoleApp1.FooFactoryOther, Reuse=Singleton {Lifespan=1000}})**

使用属性或字段

使用实例对象的属性

示例 :Made.Of 指定实例的属性

  • 使用 ServiceInfo.Of 方法指定工厂类型 ```csharp public interface IFoo {} public class Foo : IFoo { public Foo(Repo repo) {} } public class Repo {}

public class FooFactory { public IFoo Foo { get; private set; } public FooFactory(Repo repo) { Foo = new Foo(repo); } }

var c = new Container(); c.Register(); c.Register(Reuse.Singleton); c.Register(made: Made.Of(r => ServiceInfo.Of(), f => f.Foo)); Assert.IsNotNull(c.Resolve());

  1. <a name="YeO8Y"></a>
  2. # 使用泛型工厂方法
  3. <a name="6BJrW"></a>
  4. ## 泛型注册支持工厂方法
  5. <a name="hht9g"></a>
  6. #### 示例 :Made.Of 运用于泛型支持
  7. ```csharp
  8. public interface IService<A, B>
  9. {
  10. void Initialize(A a);
  11. }
  12. public class ServiceImpl<A, B> : IService<A, B>
  13. {
  14. public void Initialize(A a) {}
  15. }
  16. public class Foo {}
  17. [Export]
  18. public class Factory<A>
  19. {
  20. [Export]
  21. public IService<A, B> Create<B>(A a)
  22. {
  23. var service = new ServiceImpl<A, B>();
  24. service.Initialize(a);
  25. return service;
  26. }
  27. }
  28. var container = new Container();
  29. container.Register<Foo>();
  30. container.Register(typeof(Factory<>));
  31. container.Register(typeof(IService<,>),made: Made.Of(typeof(Factory<>).GetSingleMethodOrNull("Create"), ServiceInfo.Of(typeof(Factory<>))));
  32. Assert.IsNotNull(container.Resolve<IService<Foo, string>>());