使用构造函数
使用“表达式”指定构造函数
示例 :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
// 使用 Make.Of 方法,通过“表达式”指定构造函数// 使用 Arg.Of 方法,通过“表达式“指定构造函数的参数类型// new Foo(Arg.Of<IDependency>()) 并不会执行创建对象,仅作为“表达式”c.Register<Foo>(made: Made.Of(() => new Foo(Arg.Of<IDependency>())));Assert.IsNotNull(c.Resolve<Foo>());}
}
**Made.Of 源码:**- serviceReturningExpr 参数类型为 **System.Linq.Expressions.Expression<Func<TService>>**,表明该参数是一个linq表达式,并非用于真实执行的委托代码。- argValues 参数类型为 **params Func<Request, object>[]**,用于为依赖提供参数值(可选)。- TypeMade 方法其本质是通过 **FromExpression **方法解构表达式。```csharppublic static TypedMade<TService> Of<TService>(System.Linq.Expressions.Expression<Func<TService>> serviceReturningExpr,params Func<Request, object>[] argValues) =>FromExpression<TService>(member => _ => DryIoc.FactoryMethod.Of(member), serviceReturningExpr, argValues);
FromExpression 源码:(Linq 相关的知识)**
private static TypedMade<TService> FromExpression<TService>(Func<MemberInfo, FactoryMethodSelector> getFactoryMethodSelector,System.Linq.Expressions.LambdaExpression serviceReturningExpr, params Func<Request, object>[] argValues){var callExpr = serviceReturningExpr.ThrowIfNull().Body;if (callExpr.NodeType == System.Linq.Expressions.ExpressionType.Convert) // proceed without Cast expression.return FromExpression<TService>(getFactoryMethodSelector,System.Linq.Expressions.Expression.Lambda(((System.Linq.Expressions.UnaryExpression)callExpr).Operand,Empty<System.Linq.Expressions.ParameterExpression>()),argValues);MemberInfo ctorOrMethodOrMember;IList<System.Linq.Expressions.Expression> argExprs = null;IList<System.Linq.Expressions.MemberBinding> memberBindingExprs = null;ParameterInfo[] parameters = null;if (callExpr.NodeType == System.Linq.Expressions.ExpressionType.New ||callExpr.NodeType == System.Linq.Expressions.ExpressionType.MemberInit){var newExpr = callExpr as System.Linq.Expressions.NewExpression ?? ((System.Linq.Expressions.MemberInitExpression)callExpr).NewExpression;ctorOrMethodOrMember = newExpr.Constructor;parameters = newExpr.Constructor.GetParameters();argExprs = newExpr.Arguments;if (callExpr is System.Linq.Expressions.MemberInitExpression)memberBindingExprs = ((System.Linq.Expressions.MemberInitExpression)callExpr).Bindings;}else if (callExpr.NodeType == System.Linq.Expressions.ExpressionType.Call){var methodCallExpr = (System.Linq.Expressions.MethodCallExpression)callExpr;ctorOrMethodOrMember = methodCallExpr.Method;parameters = methodCallExpr.Method.GetParameters();argExprs = methodCallExpr.Arguments;}else if (callExpr.NodeType == ExprType.Invoke){var invokeExpr = (System.Linq.Expressions.InvocationExpression)callExpr;var invokedDelegateExpr = invokeExpr.Expression;var invokeMethod = invokedDelegateExpr.Type.GetTypeInfo().GetDeclaredMethod(nameof(Action.Invoke));ctorOrMethodOrMember = invokeMethod;parameters = invokeMethod.GetParameters();argExprs = invokeExpr.Arguments;}else if (callExpr.NodeType == System.Linq.Expressions.ExpressionType.MemberAccess){var member = ((System.Linq.Expressions.MemberExpression)callExpr).Member;Throw.If(!(member is PropertyInfo) && !(member is FieldInfo),Error.UnexpectedFactoryMemberExpressionInMadeOf, member, serviceReturningExpr);ctorOrMethodOrMember = member;}else return Throw.For<TypedMade<TService>>(Error.NotSupportedMadeOfExpression, callExpr);var hasCustomValue = false;var parameterSelector = parameters.IsNullOrEmpty() ? null: ComposeParameterSelectorFromArgs(ref hasCustomValue,serviceReturningExpr, parameters, argExprs, argValues);var propertiesAndFieldsSelector =memberBindingExprs == null || memberBindingExprs.Count == 0 ? null: ComposePropertiesAndFieldsSelector(ref hasCustomValue,serviceReturningExpr, memberBindingExprs, argValues);return new TypedMade<TService>(getFactoryMethodSelector(ctorOrMethodOrMember),parameterSelector, propertiesAndFieldsSelector, hasCustomValue);}
使用“反射”指定构造函数
示例 :Made.Of 使用“反射”指定构造函数
使用 Register 方法注册类型时,通过 Type 类的 GetConstructor 方法 指定构造函数,在 Resolve 对象时,使用该构造函数创建对象。
class Register_with_reflection{[Test]public void Example(){var c = new Container();c.Register<IDependency, Dep>();// 使用 Type 类型的 GetConstructor 方法返回指定的构造函数c.Register<Foo>(made: Made.Of(typeof(Foo).GetConstructor(new[] { typeof(IDependency) })));Assert.IsNotNull(c.Resolve<Foo>());}}
注意:当注册泛型类型时仅能使用以下这种方法
示例 :Made.Of 使用“反射”为泛型类型指定构造函数
public interface IDependency<T> { }public class Foo<T>{public IDependency<T> Dep { get; }public Foo(IDependency<T> dep) => Dep = dep;}public class Dep<T> : IDependency<T> {}class Register_open_generics_with_reflection{[Test]public void Example(){var c = new Container();c.Register<IDependency<int>, Dep<int>>();// 通过 Type 类的 GetConstructors 方法,获取第一个构造函数c.Register(typeof(Foo<>), made: Made.Of(typeof(Foo<>).GetConstructors()[0]));Assert.IsNotNull(c.Resolve<Foo<int>>());}}
根据方法参数选择用于解析的构造函数
DryIoc 支持根据解析的参数来选择合适的构造函数。先从参数数量最大的构造函数开始匹配,若无法正确解析参数,则选择下一个参数更少的构造函数,以此类推。若最终无法取得构造函数,则抛出异常。
示例 :FactoryMethod.ConstructorWithResolvableArguments 参数
根据可解析的参数查找构造函数,若查找失败则抛出异常。
使用 Register 方法,为指定“服务类”设置 FactoryMethod.ConstructorWithResolvableArguments。(即无需指定构造函数)
class Register_with_automatic_constructor_selection{[Test]public void Example(){var c = new Container();c.Register<IDependency, Dep>();c.Register<Foo>(made: FactoryMethod.ConstructorWithResolvableArguments);Assert.IsNotNull(c.Resolve<Foo>());}}
使用 rules.With 方法,为 container 所有“服务类”设置 FactoryMethod.ConstructorWithResolvableArguments。(即无需指定构造函数)
class Register_with_automatic_constructor_selection_for_entire_container{[Test]public void Example(){var c = new Container(rules => rules.With(FactoryMethod.ConstructorWithResolvableArguments));c.Register<IDependency, Dep>();c.Register<Foo>(); // no need to specify how to select constructorAssert.IsNotNull(c.Resolve<Foo>());}}
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); //… }
<a name="1heY8"></a># 使用工厂方法(代替构造函数)> DryIoc directly supports static or instance factory methods. Container will inject dependencies into method parameters the same way as for constructors.> DryIcom 原生支持静态的或实例的工厂方法。容器采用类似注入构造函数参数的方式为工厂方法注入参数。<a name="uO4Kg"></a>## 静态工厂方法<a name="ZTqvd"></a>#### 示例 :Made.Of 方法 指定静态工厂函数- 使用 Register 方法注册类型时,将某静态方法指定工厂方法,在 Resolve 对象时,使用该工厂方法创建对象```csharppublic interface IFoo {}public class FooBar : IFoo {}public class Repo{public void Add(IFoo foo) {}}public static class FooFactory{public static IFoo CreateFoo(Repo repo){var foo = new FooBar();repo.Add(foo);return foo;}}var c = new Container();c.Register<Repo>();// 使用工厂静态方法作FooFactory.CreateFoo,该代码并不执行创建对象,仅作为“表达式”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) { }
public IFoo CreateFoo(Repo repo){var foo = new FooBar();repo.Add(foo);return foo;}
}
var c = new Container();
// 为 IFooFactory 注册 FooFactory
c.Register
<a name="e0ppt"></a>#### 疑问 :如果“服务类”(IFooFactory)注册多个“实现类”,此时运行程序将会如何?- 新增 FooFactoryOther 类继承自 IFooFactory 接口,同时在 container 中注册该类型为单例模式```csharp// 新增一个“实现类”public class FooFactoryOther : IFooFactory{public FooFactoryOther(IDependency dep) { }public IFoo CreateFoo(Repo repo){var foo = new FooBar();repo.Add(foo);return foo;}}var c = new Container();c.Register<IFooFactory, FooFactory>(Reuse.Singleton);c.Register<IFooFactory, FooFactoryOther>(Reuse.Singleton);c.Register<IDependency, Dep>();c.Register<Repo>();c.Register<IFoo>(made: Made.Of(r => ServiceInfo.Of<IFooFactory>(), f => f.CreateFoo(Arg.Of<Repo>())));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
<a name="YeO8Y"></a># 使用泛型工厂方法<a name="6BJrW"></a>## 泛型注册支持工厂方法<a name="hht9g"></a>#### 示例 :Made.Of 运用于泛型支持```csharppublic interface IService<A, B>{void Initialize(A a);}public class ServiceImpl<A, B> : IService<A, B>{public void Initialize(A a) {}}public class Foo {}[Export]public class Factory<A>{[Export]public IService<A, B> Create<B>(A a){var service = new ServiceImpl<A, B>();service.Initialize(a);return service;}}var container = new Container();container.Register<Foo>();container.Register(typeof(Factory<>));container.Register(typeof(IService<,>),made: Made.Of(typeof(Factory<>).GetSingleMethodOrNull("Create"), ServiceInfo.Of(typeof(Factory<>))));Assert.IsNotNull(container.Resolve<IService<Foo, string>>());
