前言
上一篇文章介绍IOptions的注册,本章我们继续往下看
IOptions
IOptions是一个接口里面只有一个Values属性,该接口通过OptionsManager实现
public interface IOptionswhere TOptions : class, new() { ////// The default configuredinstance ///TOptions Value { get; } }
OptionsManager
OptionsManager实现了IOptions<>和IOptionsSnapshot<>,他使用内部属性OptionsCache
public class OptionsManager: IOptions, IOptionsSnapshotwhere TOptions : class, new() { private readonly IOptionsFactory_factory; private readonly OptionsCache_cache = new OptionsCache(); // Note: this is a private cache ////// Initializes a new instance with the specified options configurations. //////The factory to use to create options.public OptionsManager(IOptionsFactoryfactory) { _factory = factory; } ////// The default configuredinstance, equivalent to Get(Options.DefaultName). ///public TOptions Value { get { return Get(Options.DefaultName); } } ////// Returns a configuredinstance with the given. ///public virtual TOptions Get(string name) { name = name ?? Options.DefaultName; // Store the options in our instance cache return _cache.GetOrAdd(name, () => _factory.Create(name)); } } public interface IOptionsSnapshot: IOptionswhere TOptions : class, new() { ////// Returns a configuredinstance with the given name. ///TOptions Get(string name); }
OptionsCache
OptionsCache采用了线程安全字典ConcurrentDictionary进行了封装用于内存缓存
public class OptionsCache: IOptionsMonitorCachewhere TOptions : class { private readonly ConcurrentDictionary<string, Lazy> _cache = new ConcurrentDictionary<string, Lazy>(StringComparer.Ordinal); ////// Clears all options instances from the cache. ///public void Clear() => _cache.Clear(); ////// Gets a named options instance, or adds a new instance created with. //////The name of the options instance.///The func used to create the new instance.///The options instance.public virtual TOptions GetOrAdd(string name, FunccreateOptions) { if (createOptions == null) { throw new ArgumentNullException(nameof(createOptions)); } name = name ?? Options.DefaultName; return _cache.GetOrAdd(name, new Lazy(createOptions)).Value; } ////// Tries to adds a new option to the cache, will return false if the name already exists. //////The name of the options instance.///The options instance.///Whether anything was added.public virtual bool TryAdd(string name, TOptions options) { if (options == null) { throw new ArgumentNullException(nameof(options)); } name = name ?? Options.DefaultName; return _cache.TryAdd(name, new Lazy(() => options)); } ////// Try to remove an options instance. //////The name of the options instance.///Whether anything was removed.public virtual bool TryRemove(string name) { name = name ?? Options.DefaultName; return _cache.TryRemove(name, out var ignored); } }
OptionsFactory
OptionsFactory实现了 IOptionsFactory.Create(string name);,
而OptionsFactory构造函数中注入了IConfigureOptions<>和IPostConfigureOptions<>,
这里使用了IEnumerable类型标识当注册多个时候按照次数依次的执行,从如下代码中我们也看到了我们在上一章中所说的Configures和postConfigures注册先后顺序问题。
public class OptionsFactory: IOptionsFactorywhere TOptions : class, new() { private readonly IEnumerable<IConfigureOptions> _setups; private readonly IEnumerable<IPostConfigureOptions> _postConfigures; private readonly IEnumerable<IValidateOptions> _validations; public OptionsFactory(IEnumerable<IConfigureOptions> setups, IEnumerable<IPostConfigureOptions> postConfigures) : this(setups, postConfigures, validations: null) { } public OptionsFactory(IEnumerable<IConfigureOptions> setups, IEnumerable<IPostConfigureOptions> postConfigures, IEnumerable<IValidateOptions> validations) { _setups = setups; _postConfigures = postConfigures; _validations = validations; } public TOptions Create(string name) { var options = new TOptions(); foreach (var setup in _setups) { if (setup is IConfigureNamedOptionsnamedSetup) { namedSetup.Configure(name, options); } else if (name == Options.DefaultName) { setup.Configure(options); } } foreach (var post in _postConfigures) { post.PostConfigure(name, options); } if (_validations != null) { var failures = new List(); foreach (var validate in _validations) { var result = validate.Validate(name, options); if (result.Failed) { failures.AddRange(result.Failures); } } if (failures.Count > 0) { throw new OptionsValidationException(name, typeof(TOptions), failures); } } return options; } }