前言

上一篇文章介绍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;
        }
    }