使用构造函数
使用“表达式”指定构造函数
示例 :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 **方法解构表达式。
```csharp
public 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 constructor
Assert.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 对象时,使用该工厂方法创建对象
```csharp
public 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 运用于泛型支持
```csharp
public 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>>());