【DryIOC】注册与解析

1. 术语

1.1 解析根(Resolution Root)

解析根是通过调用Resolve方法从容器中获取到的一个服务对象。以下代码中的client就是一个解析根。

var client = container.Resolve<IClient>();

1.2 注入的依赖(Injected Dependency)

void Main()
{
	var container = new Container();    
    container.Register<IClient, SomeClient>();
    container.Register<IService, SomeService>();

	var client2 = container.Resolve<IClient>();
}

public interface IService { }
public class SomeService : IService{}
public interface IClient{ IService Service { get; }}

public class SomeClient : IClient
{
	public IService Service { get; }
	public SomeClient(IService service){}
}

上面的例子中,SomeClient的构造函数中有个IService类型的参数。该参数是在调用container.Resolve<IClient>()时通过容器自动注入的,这个参数就称为类型SomeClient的注入的依赖。DryIOC支持以下类型的注入:

  • 构造注入 首选
  • 属性/字段注入不推荐

1.3 实现类型(Implementation Type)

实现类型通常为一个接口或抽象类型的具体实现类型。
1.2的例子中SomeClientSomeService就是实现类型。此外,DryIOC支持开放式泛型的实现类型:OtherService<>

1.4 服务类型(Service Type)

服务类型通常为一个接口或抽象类型。此外,可以使用实现类型作为服务类型。DryIOC亦支持开放式服务类型:IService<>

2. 注册API

DryIOC使用Register...方法进行注册。

2.1 常规注册

var container = new Container();
 container.Register<IClient, SomeClient>();
 container.Register<IService, SomeService>();

2.2 类型参数注册

如果在编译时不知道具体的类型,可以使用以下方式进行注册:

var container = new Container();
container.Register(typeof(IClient), typeof(SomeClient));
container.Register(typeof(IService), typeof(SomeService));

2.3 开放式泛型注册

void Main()
{
	var container = new Container();
	container.Register(typeof(IService<>), typeof(SomeService<>));
	var s = container.Resolve<IService<string>>();
}

interface IService<T> { }
class SomeService<T> : IService<T> { }

2.4 实现类型作为服务类型

var container = new Container();
// 以下两种方式等价
container.Register<SomeService>();
container.Register(typeof(SomeService));

2.5 底层的注册API

上述所使用的API都是通过对通过一个底层注册API的高层封装,这个底层API定义在 IRegistrator 接口中。

void Register(Factory factory, 
              Type serviceType, 
              object serviceKey, 
              IfAlreadyRegistered? ifAlreadyRegistered, 
              bool isStaticallyChecked);

DryIoc中的工厂是一个实体,它保存创建服务所需的所有信息和行为。Factory是一个抽象类,DryIOC中实现的工厂如下:

  • ReflectionFactory
  • DelegateFactory
  • ExpressionFactory
void Main()
{
	var container = new Container();
	container.Register(typeof(IA), new ReflectionFactory(typeof(A), Reuse.Singleton));
	
	var a = container.Resolve<IA>();
}

interface IA { }
class A : IA { }

3. 单例注册

将一个服务类型注册为单例模式后,无论是通过解析或注册该服务类型所对应的实现类型,都将得到相同的实例。

var container = new Container();
container.Register<IClient, SomeClient>();
container.Register<IService, SomeService>(Reuse.Singleton); // 单例注册

// 获取两个实例,但是这两个实例都的注入依赖是单例的,因此注入的依赖是同一个实例
var one = container.Resolve<IClient>();
var two = container.Resolve<IClient>();
Console.WriteLine(two.Service == one.Service); // True

4. 注册多个实现

分为两种情况,一是默认注册,一是关键字注册。

4.1 默认注册

不能通过获取直接的实现类型,而需要获取所有对应服务类型的实现类型的集合。

void Main()
{
	var container = new Container();
    container.Register<ICommand, GetCommand>();
    container.Register<ICommand, SetCommand>();
    container.Register<ICommand, DeleteCommand>();

	// 直接解析服务会发生异常,因为通过一个服务类型注册了多个实现类型。容器不清楚该创建哪一个实现类型的实例
    // container.Resolve<ICommand>(); 

	// 可通过以下两种方式进行获取所有注册的实现类型的集合
	// 方式一
	// 支持数组或数组所实现的接口
    Console.WriteLine(container.Resolve<IEnumerable<ICommand>>().Count()); // 3
	Console.WriteLine(container.Resolve<ICommand[]>().Count());
	Console.WriteLine(container.Resolve<IList<ICommand>>().Count());
	Console.WriteLine(container.Resolve<ICollection<ICommand>>().Count());
	Console.WriteLine(container.Resolve<IReadOnlyList<ICommand>>().Count());
	Console.WriteLine(container.Resolve<IReadOnlyCollection<ICommand>>().Count());

	// 方式二
    Console.WriteLine(container.ResolveMany<ICommand>().Count()); // 3
}

internal interface ICommand { }
internal class GetCommand : ICommand { }
internal class SetCommand : ICommand { }
internal class DeleteCommand : ICommand { }

使用默认方式注册多个实现类型,DryIOC内部使用一个类型为DefaultKey的特殊键值进行区分

解析获取的实现类型集合中实现类型的顺序与注册时的顺序相同

可以通过以下方式选择某个实现类型,以避免调用Resolve<ICommand>时发生异常。

  • 注册时使用条件参数
    使用这种方式,虽然为一个服务类型注册了多个实现类型,但是仅能获取其中一种实现类型的实例
void Main()
{
	var container = new Container();
    container.Register<ICommand, GetCommand>(setup: Setup.With(condition: req => req.IsResolutionRoot));
    container.Register<ICommand, SetCommand>(setup: Setup.With(condition: req => !req.IsResolutionRoot));
    container.Register<ICommand, DelCommand>(setup: Setup.With(condition: req => !req.IsResolutionRoot));

    Console.WriteLine(container.Resolve<ICommand>() is GetCommand); // True
}

internal interface ICommand { }
internal class GetCommand : ICommand { }
internal class SetCommand : ICommand { }
internal class DelCommand : ICommand { }
  • 指定元数据类型
    通过元数据进行结果筛选,每次都是获取一个集合,效率上有所降低。
void Main()
{
	var container = new Container();
    container.Register<ICommand, GetCommand>(setup: Setup.With(metadataOrFuncOfMetadata: CommandId.Get));
    container.Register<ICommand, SetCommand>(setup: Setup.With(metadataOrFuncOfMetadata: CommandId.Set));
    container.Register<ICommand, DelCommand>(setup: Setup.With(metadataOrFuncOfMetadata: CommandId.Del));

	container.Resolve<IEnumerable<Meta<ICommand, CommandId>>>().Dump();
	
    Console.WriteLine(container.Resolve<IEnumerable<Meta<ICommand, CommandId>>>().FirstOrDefault(m => m.Metadata == CommandId.Get).Value is GetCommand); // True
	Console.WriteLine(container.Resolve<IEnumerable<Meta<ICommand, CommandId>>>().FirstOrDefault(m => m.Metadata == CommandId.Set).Value is SetCommand); // True
	Console.WriteLine(container.Resolve<IEnumerable<Meta<ICommand, CommandId>>>().FirstOrDefault(m => m.Metadata == CommandId.Del).Value is DelCommand); // True
}

interface ICommand {}
class GetCommand : ICommand {}
class SetCommand : ICommand {}
class DelCommand : ICommand {}
enum CommandId { Get, Set, Del }

在这里插入图片描述

  • 使用重用方式边界来指定父作用域,或命名作用域
    当指定的作用域被释放时,该作用域所存储的实现类型亦被释放。
void Main()
{
	var container = new Container();
    container.Register<ICommand, GetCommand>(reuse:Reuse.ScopedTo("Get"));
    container.Register<ICommand, SetCommand>(reuse:Reuse.ScopedTo("Set"));
    container.Register<ICommand, DelCommand>(reuse:Reuse.ScopedTo("Del"));

	using(var getScope = container.OpenScope(name:"Get"))
	{
		Console.WriteLine(getScope.Resolve<ICommand>() is GetCommand); // True
	}

	using (var setScope = container.OpenScope(name: "Set"))
	{
		Console.WriteLine(setScope.Resolve<ICommand>() is SetCommand); // True
	}

	using (var delScope = container.OpenScope(name: "Del"))
	{
		Console.WriteLine(delScope.Resolve<ICommand>() is DelCommand); // True
	}
}
  • 使用关键字注册
    下一章节进行说明

4.2 关键字注册

在注册时提供一个服务关键字。该关键字是任意实现了Object.GetHashCodeObject.Equals的类型。通常使用enumstringnumber

void Main()
{
	var container = new Container();
    container.Register<ICommand, GetCommand>(serviceKey: CommandId.Get);
    container.Register<ICommand, SetCommand>(serviceKey: CommandId.Set);
    container.Register<ICommand, DelCommand>(serviceKey: CommandId.Del);

	Console.WriteLine(container.Resolve<ICommand>(serviceKey: CommandId.Get) is GetCommand); // True
	Console.WriteLine(container.Resolve<ICommand>(serviceKey: CommandId.Set) is SetCommand); // True
	Console.WriteLine(container.Resolve<ICommand>(serviceKey: CommandId.Del) is DelCommand); // True
}

interface ICommand { }
class GetCommand : ICommand { }
class SetCommand : ICommand { }
class DelCommand : ICommand { }
enum CommandId { Get, Set, Del }

LazyFunc结合使用。

void Main()
{
	var container = new Container();
    container.Register<ICommand, GetCommand>(serviceKey: CommandId.Get);
    container.Register<ICommand, SetCommand>(serviceKey: CommandId.Set);
    container.Register<ICommand, DelCommand>(serviceKey: CommandId.Del);

	var commands = container.Resolve<KeyValuePair<CommandId, ICommand>[]>();
	commands.Dump(nameof(commands));
	
	var lazyCommands = container.Resolve<KeyValuePair<CommandId, Lazy<ICommand>>[]>();
	lazyCommands.Dump(nameof(lazyCommands));

	var commandFactories = container.Resolve<KeyValuePair<CommandId, Func<ICommand>>[]>();
	commandFactories.Dump(nameof(commandFactories));
}

interface ICommand { }
class GetCommand : ICommand { }
class SetCommand : ICommand { }
class DelCommand : ICommand { }
enum CommandId { Get, Set, Del }

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.3 KeyValuePair 封装

DryIOC支持将已注册的服务解析为对应的服务关键字的键值对KeyValuePair<KeyType, ServiceType>。这种模式能够工作于默认模式和关键字模式,因为默认模式下内部使用类型为DefaultKey的键。

当解析一个服务集合时,如果集合中的服务类型的键值的类型不同,需要使用object作为KeyType的类型。

void Main()
{
	var container = new Container();
	container.Register<I, X>();
	container.Register<I, Y>();
	container.Register<I, Z>(serviceKey: "z");

	// 使用object类型作为键的类型,获取所有实现类型
	var allItems = container.Resolve<KeyValuePair<object, I>[]>();
	allItems.Dump(nameof(allItems));

	// 获取默认键值的实现对象集合
	var defaultItems = container.Resolve<KeyValuePair<DefaultKey, I>[]>();
	defaultItems.Dump(nameof(defaultItems));

	// 获取指定键值类型的实现对象集合
	var stringItems = container.Resolve<KeyValuePair<string, I>[]>();
	stringItems.Dump(nameof(stringItems));
}

interface I { }
class X : I { }
class Y : I { }
class Z : I { }

在这里插入图片描述

注意
DryIOC不保证非默认关键字注册的实现类型在解析树的集合中出现的顺序。例如,上例中z关键字在最后注册,但可能出现在集合中非最后的位置。

5. 判断一个服务是否已经被注册

5.1 检查服务是否注册

DryIOC使用IsRegistered方法测试一个服务、装饰器或封装器是否被注入到容器。此外,IsRegistered允许提供一个条件参数来测试服务的工厂实现,即能够测试一份注册服务的相关信息。

void Main()
{
	var c = new Container();
    // 未注册时
	Console.WriteLine(c.IsRegistered<MyService>());                                                      // False
    Console.WriteLine(c.IsRegistered<MyService>(condition: factory => factory.Reuse is SingletonReuse)); // False

    c.Register<MyService>();

    // 注册但非单例
    Console.WriteLine(c.IsRegistered<MyService>());                                                      // True
    Console.WriteLine(c.IsRegistered<MyService>(condition: factory => factory.Reuse is SingletonReuse)); // False

    c.Register<MyService>(Reuse.Singleton);

	// 注册单例
	Console.WriteLine(c.IsRegistered<MyService>(condition: factory => factory.Reuse is SingletonReuse)); // True
	
	// 对一个服务注册不同的重用类型,将使用最后一个注册
	Console.WriteLine(c.Resolve<MyService>() == c.Resolve<MyService>());                                 // True
}
class MyService { }

5.2 检查是否注册默认键类型或关键字类型

默认情况下,IsRegistered检查所有类型的注册。如果期望仅对默认注册或关键字注册进行检查,请看如下例程。

void Main()
{
	var c = new Container();
	// 关键字注册
    c.Register<MyService>(serviceKey: "the key");

	// 检查一个服务是否通过指定关键字进行注册
    Console.WriteLine(c.IsRegistered<MyService>(serviceKey: "the key")); 		// True
	// 检查是否存在默认键注册的类型
    Console.WriteLine(c.IsRegistered<MyService>(serviceKey: DefaultKey.Value)); // False
	// 如果没有服务关键字,将检查所有类型的注册
	Console.WriteLine(c.IsRegistered<MyService>());								// True

	// 默认注册
    c.Register<MyService>();
	
	// 检查是否存在默认键注册的类型
	Console.WriteLine(c.IsRegistered<MyService>(serviceKey: DefaultKey.Value)); // True
}
class MyService { }

5.3 检查装饰器或封装其是否被注册

默认情况,IsRegistered仅检查服务是否被注册,而不去检测装饰器封装器。如果要实现装饰器封装器是否注册的检查功能,需要指定对应的FactoryType

void Main()
{
	var c = new Container();
	Console.WriteLine(c.IsRegistered(typeof(Owned<>), factoryType: FactoryType.Wrapper)); // False

	c.Register(typeof(Owned<>), setup: Setup.Wrapper);
	Console.WriteLine(c.IsRegistered(typeof(Owned<>), factoryType: FactoryType.Wrapper)); // True
}
class Owned<T> { }

IsRegistered不检查一个实现类型是否可以被成功解析

5.4 检查一个类型是否可解析

如果一个类型被注册,但是其依赖未被注册,通过IfUnresolved.ReturnDefault检查其可解析性。

void Main()
{
	var c = new Container();
    Console.WriteLine(c.Resolve<MyService>(ifUnresolved: IfUnresolved.ReturnDefault) != null);

    c.Register<MyService>();
    Console.WriteLine(c.Resolve<MyService>(ifUnresolved: IfUnresolved.ReturnDefault) != null);

	// 如果仅仅是判断解析性而不需要创建实例,使用Func进行封装
	Console.WriteLine(c.Resolve<Func<MyService>>(ifUnresolved: IfUnresolved.ReturnDefault) != null);
}
class MyService { }

5.5 显示地检查一个服务是否被注册

基本思想是获取容器内的所有注册,然后根据指定条件进行筛选。

void Main()
{
	var c = new Container();
    c.Register<MyService>(Reuse.Scoped, serviceKey: "foo");

    var serviceRegistration = c.GetServiceRegistrations().FirstOrDefault(r => Equals(r.OptionalServiceKey, "foo") && r.Factory.Reuse == Reuse.Scoped);

    Console.WriteLine(typeof(MyService) == serviceRegistration.ImplementationType); // True
}
class MyService { }

6. RegisterMany

有时一个实现类型实现了多个服务类型,这时的注册可以分成多种情况。

6.1 使用实现类型,同时注册本身及其实现接口``

void Main()
{
    var container = new Container(); 

	// 使用实现类型A,同时注册本身及其实现接口
    container.RegisterMany<A>();
	Console.WriteLine(container.IsRegistered(typeof(X))); // True
	Console.WriteLine(container.IsRegistered(typeof(Y))); // True
	Console.WriteLine(container.IsRegistered(typeof(A))); // True
}
public interface X { }
public interface Y { }
public class A : X, Y { }

6.2 使用实现类型,仅注册其实现接口

void Main()
{
    var container = new Container();
	
	container.RegisterMany<A>(serviceTypeCondition: type => type.IsInterface);
	
	Console.WriteLine(container.IsRegistered(typeof(X))); // True
	Console.WriteLine(container.IsRegistered(typeof(Y))); // True
	Console.WriteLine(container.IsRegistered(typeof(A))); // False
}
public interface X { }
public interface Y { }
public class A : X, Y { }

6.3 接口与实现共享实例

void Main()
{
    var container = new Container();
	
	container.RegisterMany<A>(Reuse.Singleton);
	
	Console.WriteLine(container.Resolve<X>() == container.Resolve<Y>()); // True
	Console.WriteLine(container.Resolve<X>() == container.Resolve<A>()); // True
	Console.WriteLine(container.Resolve<Y>() == container.Resolve<A>()); // True
}
public interface X { }
public interface Y { }
public class A : X, Y { }

6.4 用接口X与Y注册A,接口X注册B

void Main()
{
    var container = new Container(rules => rules.WithTrackingDisposableTransients());

	container.RegisterMany(new[] { typeof(A), typeof(B) }, serviceTypeCondition: type => type.IsInterface);

	// 此时服务类型X对应的实现类型有多个,因此不能直接的使用Resolve<X>进行解析
	container.Resolve<X[]>().Dump("X");
	container.Resolve<Y>().Dump("Y");
}
public interface X { }
public interface Y { }
public class A : X, Y { }
public class B : X, IDisposable
{
	public void Dispose() { }
}

在这里插入图片描述

6.5 用X接口注册A与B

void Main()
{
    var container = new Container(rules => rules.WithTrackingDisposableTransients());

	container.RegisterMany(new[] { typeof(A), typeof(B) }, serviceTypeCondition: type => type == typeof(X));
	Console.WriteLine(container.IsRegistered(typeof(X))); // True
	Console.WriteLine(container.IsRegistered(typeof(Y))); // False
	Console.WriteLine(container.IsRegistered(typeof(A))); // False
	Console.WriteLine(container.IsRegistered(typeof(B))); // False

	// 此时服务类型X对应的实现类型有多个,因此不能直接的使用Resolve<X>进行解析
	container.Resolve<X[]>().Dump("X");
}
public interface X { }
public interface Y { }
public class A : X, Y { }
public class B : X, IDisposable
{
	public void Dispose() { }
}

在这里插入图片描述

6.6 如果A与B在同一个程序集中

void Main()
{
    var container = new Container(rules => rules.WithTrackingDisposableTransients());

	container.RegisterMany(new[] { typeof(A).Assembly }, type => type == typeof(X));
	
	Console.WriteLine(container.IsRegistered(typeof(X))); // True
	Console.WriteLine(container.IsRegistered(typeof(Y))); // False
	Console.WriteLine(container.IsRegistered(typeof(A))); // False
	Console.WriteLine(container.IsRegistered(typeof(B))); // False

	// 此时服务类型X对应的实现类型有多个,因此不能直接的使用Resolve<X>进行解析
	container.Resolve<X[]>().Dump("X");
}
public interface X { }
public interface Y { }
public class A : X, Y { }
public class B : X, IDisposable
{
	public void Dispose() { }
}

6.7 使用Made.Of表达式

void Main()
{
    var container = new Container(rules => rules.WithTrackingDisposableTransients());

	container.RegisterMany(Made.Of(() => CreateA()));
	
	Console.WriteLine(container.IsRegistered(typeof(X))); // True
	Console.WriteLine(container.IsRegistered(typeof(Y))); // True
	Console.WriteLine(container.IsRegistered(typeof(A))); // True
}
public interface X { }
public interface Y { }
public class A : X, Y { }
public static A CreateA() => new A();

6.8 显示类型注册

void Main()
{
    var container = new Container(rules => rules.WithTrackingDisposableTransients());

	container.RegisterMany(new[] { typeof(X), typeof(Y) }, typeof(A));
	
	Console.WriteLine(container.IsRegistered(typeof(X))); // True
	Console.WriteLine(container.IsRegistered(typeof(Y))); // True
	Console.WriteLine(container.IsRegistered(typeof(A))); // False
}
public interface X { }
public interface Y { }
public class A : X, Y { }

6.9 通用注册

DryIOC排除某些类型作为RegisterMany函数的服务类型。这些类型包括基元类型、object、string、IDisposable、ICloneable接口等。此外,编译器生成的类型也被排除在外。

void Main()
{
    var container = new Container(rules => rules.WithTrackingDisposableTransients());

	container.RegisterMany(
		implTypeAssemblies: new[] { typeof(A).Assembly },
		getServiceTypes: implType => implType.GetImplementedServiceTypes(),
		getImplFactory: implType => new ReflectionFactory(implType, reuse: implType.IsAssignableTo<IDisposable>() ? Reuse.Scoped : Reuse.Transient, made: FactoryMethod.ConstructorWithResolvableArguments));

	Console.WriteLine(container.IsRegistered(typeof(X))); // True
	Console.WriteLine(container.IsRegistered(typeof(Y))); // True
	Console.WriteLine(container.IsRegistered(typeof(A))); // True
	Console.WriteLine(container.IsRegistered(typeof(B))); // True
}
public interface X { }
public interface Y { }
public class A : X, Y { }
public static A CreateA() => new A();
public class B : X, IDisposable
{
	public void Dispose() { }
}

7. RegisterMapping

该功能可以将一个新服务类型注册到已有的已注册的服务及其实现。

void Main()
{
	var container = new Container();
    container.Register<I, S>(Reuse.Singleton);

    container.RegisterMapping<J, I>();

	Console.WriteLine(container.IsRegistered(typeof(I)));                // True
	Console.WriteLine(container.IsRegistered(typeof(J)));                // True
	Console.WriteLine(container.Resolve<I>() == container.Resolve<J>()); // True
}

public interface I { }
public interface J { }
class S : I, J { }

8. RegisterDelegate

可以通过注册自定义的委托作为服务工厂。

void Main()
{
	var container = new Container();
	container.RegisterDelegate<IService>(resolverContext => new CheerfulService { Greetings = "Hey!" });

	var x = container.Resolve<IService>();
	Console.WriteLine(((CheerfulService)x).Greetings);
}

interface IService{	}
class CheerfulService : IService
{
	public string Greetings { get; set; }
}
void Main()
{
	var container = new Container();

	container.RegisterDelegate(_ => new GreetingsProvider { Greetings = "Mya" });
	container.RegisterDelegate<IService>(resolverContext => new CheerfulService(resolverContext.Resolve<GreetingsProvider>()));

	var x = container.Resolve<IService>();
	Console.WriteLine(((CheerfulService)x).Greetings);
}

interface IService { }

class CheerfulService : IService
{
	public string Greetings => _greetingsProvider.Greetings;

	public CheerfulService(GreetingsProvider greetingsProvider)
	{
		_greetingsProvider = greetingsProvider;
	}

	private readonly GreetingsProvider _greetingsProvider;
}

class GreetingsProvider
{
	public string Greetings { get; set; }
}

9. RegisterInstance

注册已经存在的实例到容器。

void Main()
{
	var container = new Container();
	
	var a = new A();
	container.RegisterInstance(a);
	container.Register<B>();

	var b = container.Resolve<B>();
	Console.WriteLine(a == b.A); // True
}

class A { }
class B
{
	public readonly A A;
	public B(A a) { A = a; }
}

9.1 通过Use方法将已存在的实例直接注入到当前作用域

void Main()
{
	var container = new Container();
    container.Register<B>();

    using (var scope = container.OpenScope())
	{
		var a = new A();
		scope.Use(a); // 注入到当前作用域

		var b = scope.Resolve<B>();
		Console.WriteLine(a == b.A); //True
	}

	var anotherA = new A();
	container.Use(anotherA); // 注入到单例作用域

	var anotherB = container.Resolve<B>();
	Console.WriteLine(anotherA == anotherB.A); // True
}

class A { }
class B
{
	public readonly A A;
	public B(A a) { A = a; }
}

9.2 使用Use时指定服务类型

void Main()
{
	var container = new Container();

	// 编译时类型已知
    var a = new A();
    container.Use<ISomeService>(a);

    // 运行时类型已知
    object aa = a;
    container.Use(typeof(ISomeService), aa);
}

interface ISomeService { }
class A : ISomeService { }

10. RegisterInitializer

该功能通过传入一个委托,该委托在解析方法返回前或依赖被注入前被调用。

void Main()
{
	var container = new Container();
	container.Register<Logger>(Reuse.Singleton);
	container.Register<IService, MyService>();

	container.RegisterInitializer<IService>((service, resolverContext) => resolverContext.Resolve<Logger>().Log("created"));

	container.Resolve<IService>();
	container.Resolve<Logger>().LogData.Dump();
}

interface IService { }
class MyService : IService { }

class Logger
{
	public readonly List<string> LogData = new List<string>();
	public void Log(string s) => LogData.Add(s);
}

上个例子中指定了服务的类型,如何实现对任意一个注册都有类似的日志功能?

void Main()
{
	var container = new Container();
	var loggerKey = "logger";
	container.Register<Logger>(Reuse.Singleton, serviceKey: loggerKey);
	container.Register<IService, MyService>();

	container.RegisterInitializer<object>(
	    (anyObj, resolver) => resolver.Resolve<Logger>(loggerKey).Log("created object"),
		condition: request => !loggerKey.Equals(request.ServiceKey));

	container.Resolve<IService>();
	container.Resolve<Logger>(loggerKey).LogData.Dump();
}

interface IService { }
class MyService : IService { }

class Logger
{
	public readonly List<string> LogData = new List<string>();
	public void Log(string s) => LogData.Add(s);
}

10.1 初始化使用的重用方式与实现对象的重用方式不同

默认情况下,初始化器装饰器使用的重用方式与实现对象的重用方式相同。在DryIOC v4.5.0之后新增了一个reuse参数重载,使得可以独立的控制重用方式。

void Main()
{
	var container = new Container();
	container.Register<IFoo, Boo>(Reuse.Singleton);

	var scopedUsages = 0;
	container.RegisterInitializer<IFoo>((x, r) => ++scopedUsages, Reuse.Scoped);

	using (var scope = container.OpenScope())
		scope.Resolve<IFoo>();

	using (var scope = container.OpenScope())
		scope.Resolve<IFoo>();

	using (var scope = container.OpenScope())
		scope.Resolve<IFoo>();

	Console.WriteLine(scopedUsages);
}

interface IFoo { }
class Boo : IFoo { }

11. RegisterPlaceholder

有些时候,你可能尚没有服务实现或在之后实现。在这种情况下,可以使用RegisterPlaceholder<IService>(),之后在实现类型之后,再将实现类型给与补上Register<IService, Foo>(ifAlreadyRegistered:IfAlreadyRegistered.Replace)

void Main()
{
	var container = new Container();

	container.RegisterPlaceholder<IService>();
	var getService = container.Resolve<Func<IService>>();

	container.Register<IService, Foo>(ifAlreadyRegistered: IfAlreadyRegistered.Replace);
	Console.WriteLine(getService() is Foo);
}

interface IService { }
class Foo : IService { }

12. RegisterDisposer

通常的清理工作是实现IDisposable接口。如果以Reuse的重用方式注册实现IDisposable接口的瞬态服务,当重用作用域被释放,接着服务亦被释放。

void Main()
{
	var container = new Container();

	container.Register<FileAbstraction>(Reuse.Singleton);
	container.RegisterDisposer<FileAbstraction>(f => f.CloseFile());

	var file = container.Resolve<FileAbstraction>();
	file.ReadWriteStuff();

	container.Dispose(); // will call disposer action for FileUser singleton
	Console.WriteLine(file.IsClosed);
}

internal class FileAbstraction
{
	public bool IsClosed { get; private set; }
	public void CloseFile() => IsClosed = true;

	public void ReadWriteStuff() { }
}

使用通用类型:

void Main()
{
	var container = new Container();

	container.Register<X>(Reuse.Singleton);
	container.Register<Y>(Reuse.Singleton);
	container.RegisterDisposer<IClosable>(closable => closable.Close());

	var x = container.Resolve<X>();
	var y = container.Resolve<Y>();
	container.Dispose();

	Console.WriteLine(x.IsClosed);
	Console.WriteLine(y.IsClosed);
}

interface IClosable
{
	bool IsClosed { get; }
	void Close();
}
class X : IClosable
{
	public bool IsClosed { get; private set; }
	public void Close() => IsClosed = true;
}
class Y : IClosable
{
	public bool IsClosed { get; private set; }
	public void Close() => IsClosed = true;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhy29563

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值