导航

07-002 Options 之 IOptions<out TOptions>

Posted on 2015-04-02 16:50  DotNet1010  阅读(288)  评论(0)    收藏  举报

这里先 说一下 In 和 Out

in   向内部变化 向父类变化发展  “逆变”->”逆常的变”  <string>=<object>;

out 向外部变化 向子类变化发展 “协变”->”和谐的变”  <object>=<string>;

看一下 In 的例子:

// Contravariant interface.
interface IContravariant<in A> { }

// Extending contravariant interface.
interface IExtContravariant<in A> : IContravariant<A> { }

// Implementing contravariant interface.
class Sample<A> : IContravariant<A> { }

class Program
{
    static void Test()
    {
        IContravariant<Object> iobj = new Sample<Object>();
        IContravariant<String> istr = new Sample<String>();

        // You can assign iobj to istr because
        // the IContravariant interface is contravariant.
        istr = iobj;
    }
}

 再看一下 out 的例子:

// Covariant interface.
interface ICovariant<out R> { }

// Extending covariant interface.
interface IExtCovariant<out R> : ICovariant<R> { }

// Implementing covariant interface.
class Sample<R> : ICovariant<R> { }

class Program
{
    static void Test()
    {
        ICovariant<Object> iobj = new Sample<Object>();
        ICovariant<String> istr = new Sample<String>();

        // You can assign istr to iobj because
        // the ICovariant interface is covariant.
        iobj = istr;
    }
}

 接口代码:

    public interface IOptions<out TOptions> where TOptions : class,new()
    {
        TOptions Options { get; }
        TOptions GetNamedOptions(string name);
    }

这里 实现这个接口的类有一个:

public class OptionsManager<TOptions> : IOptions<TOptions> where TOptions : class,new()

 看一下具体的代码:

public class OptionsManager<TOptions> : IOptions<TOptions> where TOptions : class,new()
    {
        private object _mapLock = new object();
        private Dictionary<string, TOptions> _namedOptions = new Dictionary<string, TOptions>(StringComparer.OrdinalIgnoreCase);
        private IEnumerable<IConfigureOptions<TOptions>> _setups;

		/// <summary>
		/// 这里是由依赖注入来传入参数的 所有实现 IConfigureOptions<TOptions> 并且添加到ServiceCollection里的对象。
		/// </summary>
		/// <param name="setups"></param>
		public OptionsManager(IEnumerable<IConfigureOptions<TOptions>> setups)
        {
            _setups = setups;
        }

        public virtual TOptions GetNamedOptions([NotNull] string name)
        {
			/*
			 这里采用了 double check locking
			 lock 里面的 判断是必须的 
			 lock 外面的 判断可以没有 但是有的话 可以提高性能 避免都在Lock内部判断
	        */
	    if (!_namedOptions.ContainsKey(name))
            {
                lock (_mapLock)
                {
                    if (!_namedOptions.ContainsKey(name))
                    {
                        _namedOptions[name] = Configure(name);
                    }
                }
            }
            return _namedOptions[name];
        }

		public virtual TOptions Configure(string optionsName = "")
		{
			return _setups == null
				? new TOptions()
				: _setups.OrderBy(setup => setup.Order)
						 .Aggregate(new TOptions(),
									(options, setup) =>
									{
										setup.Configure(options, optionsName);
										return options;
									});

			/*
			   IEnumerable<IConfigureOptions<TOptions>> setups;
			   首先将集合排序
			   看一下 Aggregate 的源代码:
			public static TAccumulate Aggregate<TSource, TAccumulate>(this IEnumerable<TSource> source, TAccumulate seed
			        , Func<TAccumulate, TSource, TAccumulate> func) {
              if (source == null) throw Error.ArgumentNull("source");
              if (func == null) throw Error.ArgumentNull("func");
               TAccumulate result = seed;
               foreach (TSource element in source) result = func(result, element);
               return result;
            }
			结合源代码来理解:
			   TOptions result =new TOptions();如果集合为空 就返回这个了;
			   foreach(IConfigureOptions<TOptions> setup  in _setups)
			   {  
			       //名字匹配才会执行
			       setup.Configure(result, optionsName);
			   }
			   return result;

	        */

		}

		public virtual TOptions Options
        {
            get
            {
                return GetNamedOptions("");
            }
        }
    }