首页 > 其他分享 >Options

Options

时间:2024-09-13 12:14:39浏览次数:8  
标签:Options name options public services class Name

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;

namespace ConsoleApp1
{
    internal class Program
    {

        /*
         *  1. IOptions单例,获取的值是同一个实例
         *  2. IOptionsSnapshot scope, 每次请求获取的值是不同的实例,但是在生命周期内是同一个实例
         *  3. IOptionsMonitor单例,获取的值是同一个实例,当配置发生变化时,会更新实例
         *  
         *  4. Configure<>, ConfigureOptions<>, AddOptions<> 三者的区别:
         *     4.1 Configure<> 使用ConfigureNamedOptions配置选项
         *     4.2 ConfigureOptions<> 使用自定义IConfigureNamedOptions
         *     4.3 AddOptions<>, 使用ConfigureNamedOptions<T, Dep>配置选项,使其可以依赖注入
         */
        static async Task Main(string[] args)
        {
            var services = new ServiceCollection();
            services.MyConfigure<MyOptions>(x => x.Name = new Random().Next(10000).ToString());



            var provider = services.BuildServiceProvider();

            var opt1 = provider.GetRequiredService<IOptions<MyOptions>>();
            Console.WriteLine(opt1.Value.Name);

            var opt2 = provider.GetRequiredService<IOptions<MyOptions>>();
            Console.WriteLine(opt2.Value.Name);

            var opt3 = provider.GetRequiredService<IOptionsSnapshot<MyOptions>>();
            Console.WriteLine(opt3.Get(Options.DefaultName).Name);

            var opt4 = provider.GetRequiredService<IOptionsSnapshot<MyOptions>>();
            Console.WriteLine(opt4.Get(Options.DefaultName).Name);



            using var scope = provider.CreateScope();
            var scopeProvider = scope.ServiceProvider;

            var opt11 = scopeProvider.GetRequiredService<IOptions<MyOptions>>();
            Console.WriteLine(opt11.Value.Name);

            var opt21 = scopeProvider.GetRequiredService<IOptions<MyOptions>>();
            Console.WriteLine(opt21.Value.Name);

            var opt31 = scopeProvider.GetRequiredService<IOptionsSnapshot<MyOptions>>();
            Console.WriteLine(opt31.Get(Options.DefaultName).Name);

            var opt41 = scopeProvider.GetRequiredService<IOptionsSnapshot<MyOptions>>();
            Console.WriteLine(opt41.Get(Options.DefaultName).Name);

            Console.ReadKey();
        }
    }

    public class MyOptions
    {
        public string Name { get; set; }
    }

    public interface IOptions<T>
    {
        T Value { get; }
    }

    public interface IConfigureOptions<T> where T : class
    {
        void Configure(T config);
    }

    public interface IConfigureNamedOptions<T> : IConfigureOptions<T> where T : class
    {
        void Configure(string? name, T options);
    }

    public interface IPostConfigureOptions<T> where T : class
    {
        void PostConfigure(string? name, T options);
    }

    public interface IOptionsFactory<T> where T : class
    {
        T Create(string name);
    }

    public interface IOptionsSnapshot<T> where T : class
    {
        T Get(string? name);
    }


    public interface IOptionsMonitor<T> where T : class
    {
        T CurrentValue { get; }
        T Get(string? name);
        IDisposable? OnChange(Action<T, string?> listener);
    }

    public interface IOptionsChangeTokenSource<T> where T : class
    {
        IChangeToken GetChangeToken();
        string? Name { get; }
    }

    public class ConfigureNamedOptions<T> : IConfigureNamedOptions<T> where T : class
    {
        public ConfigureNamedOptions(string? name, Action<T>? action)
        {
            Name = name;
            Action = action;
        }

        public string? Name { get; }

        public Action<T>? Action { get; }


        public virtual void Configure(string? name, T options)
        {
            // Null name is used to configure all named options.
            if (Name == null || name == Name)
            {
                Action?.Invoke(options);
            }
        }

        public void Configure(T options) => Configure(Options.DefaultName, options);
    }

    public class ConfigureNamedOptions<TOptions, TDep> : IConfigureNamedOptions<TOptions>
        where TOptions : class
        where TDep : class
    {
        public ConfigureNamedOptions(string? name, TDep dependency, Action<TOptions, TDep>? action)
        {
            Name = name;
            Action = action;
            Dependency = dependency;
        }

        public string? Name { get; }

        public Action<TOptions, TDep>? Action { get; }

        public TDep Dependency { get; }

        public virtual void Configure(string? name, TOptions options)
        {
            // Null name is used to configure all named options.
            if (Name == null || name == Name)
            {
                Action?.Invoke(options, Dependency);
            }
        }

        public void Configure(TOptions options) => Configure(Options.DefaultName, options);
    }

    public class PostConfigureOptions<T> : IPostConfigureOptions<T> where T : class
    {
        public PostConfigureOptions(string? name, Action<T>? action)
        {
            Name = name;
            Action = action;
        }

        public string? Name { get; }

        public Action<T>? Action { get; }

        public virtual void PostConfigure(string? name, T options)
        {
            if (Name == null || name == Name)
            {
                Action?.Invoke(options);
            }
        }
    }

    public class OptionsFactory<T> : IOptionsFactory<T> where T : class
    {
        private readonly IConfigureOptions<T>[] _setups;
        private readonly IPostConfigureOptions<T>[] _postConfigures;

        public OptionsFactory(IEnumerable<IConfigureOptions<T>> setups, IEnumerable<IPostConfigureOptions<T>> postConfigures)
        {
            _setups = setups as IConfigureOptions<T>[] ?? new List<IConfigureOptions<T>>(setups).ToArray();
            _postConfigures = postConfigures as IPostConfigureOptions<T>[] ?? new List<IPostConfigureOptions<T>>(postConfigures).ToArray();
        }

        public T Create(string name)
        {
            T options = CreateInstance(name);
            foreach (IConfigureOptions<T> setup in _setups)
            {
                if (setup is IConfigureNamedOptions<T> namedSetup)
                {
                    namedSetup.Configure(name, options);
                }
                else if (name == Options.DefaultName)
                {
                    setup.Configure(options);
                }
            }
            foreach (IPostConfigureOptions<T> post in _postConfigures)
            {
                post.PostConfigure(name, options);
            }
            return options;
        }

        protected virtual T CreateInstance(string name)
        {
            return Activator.CreateInstance<T>();
        }
    }

    public class OptionsManager<T> : IOptions<T>, IOptionsSnapshot<T> where T : class
    {
        private readonly IOptionsFactory<T> _factory;
        private Dictionary<string, T> _cache = new Dictionary<string, T>();

        public OptionsManager(IOptionsFactory<T> factory)
        {
            _factory = factory;
        }

        public T Value => Get(Options.DefaultName);

        public T Get(string? name)
        {
            name = name ?? Options.DefaultName;

            if (!_cache.TryGetValue(name, out var options))
            {
                options = _factory.Create(name);
                _cache.Add(name, options);
            }
            return options;
        }
    }

    public class UnamedOptionsManager<T> : IOptions<T> where T : class
    {
        private readonly IOptionsFactory<T> _factory;
        private volatile object? _syncObj;
        private volatile T? _value;

        public UnamedOptionsManager(IOptionsFactory<T> factory)
        {
            _factory = factory;
        }

        public T Value
        {
            get
            {
                if (_value is T value) // _value is not null
                {
                    return value;
                }

                lock (_syncObj ?? Interlocked.CompareExchange(ref _syncObj, new object(), null) ?? _syncObj)
                {
                    return _value ??= _factory.Create(Options.DefaultName);
                }
            }
        }
    }

    public class OptionsMonitor<T> : IOptionsMonitor<T> where T : class
    {
        private readonly IOptionsFactory<T> _factory;
        private readonly Dictionary<string, T> _cache = new Dictionary<string, T>();
        internal event Action<T, string>? _onChange;

        public OptionsMonitor(IOptionsFactory<T> factory, IEnumerable<IOptionsChangeTokenSource<T>> sources)
        {
            _factory = factory;

            void RegisterSource(IOptionsChangeTokenSource<T> source)
            {
                IDisposable registration = ChangeToken.OnChange(
                          () => source.GetChangeToken(),
                          (name) => InvokeChanged(name),
                          source.Name);
            }

            foreach (IOptionsChangeTokenSource<T> source in sources)
            {
                RegisterSource(source);
            }
        }

        private void InvokeChanged(string? name)
        {
            name = name ?? Options.DefaultName;
            _cache.Remove(name);
            T options = Get(name);
            if (_onChange != null)
            {
                _onChange.Invoke(options, name);
            }
        }

        public T CurrentValue
        {
            get => Get(Options.DefaultName);
        }

        public T Get(string? name)
        {
            name = name ?? Options.DefaultName;

            if (!_cache.TryGetValue(name, out var options))
            {
                options = _factory.Create(name);
                _cache.Add(name, options);
            }
            return options;
        }

        public IDisposable? OnChange(Action<T, string?> listener)
        {
            throw new NotImplementedException();
        }
    }


    public class OptionsBuilder<T> where T : class
    {
        public IServiceCollection Services { get; set; }
        public string Name { get; }

        public OptionsBuilder(IServiceCollection services, string name)
        {
            this.Services = services;
            Name = name ?? Options.DefaultName;
        }

        public virtual OptionsBuilder<T> Configure(Action<T> configureOptions)
        {
            Services.AddSingleton<IConfigureOptions<T>>(new ConfigureNamedOptions<T>(Name, configureOptions));
            return this;
        }


        public virtual OptionsBuilder<T> Configure<TDep>(Action<T, TDep> configureOptions)
            where TDep : class
        {
            Services.AddTransient<IConfigureOptions<T>>(sp =>
                new ConfigureNamedOptions<T, TDep>(Name, sp.GetRequiredService<TDep>(), configureOptions));
            return this;
        }
    }

    public static class OptionsServiceCollectionExtensions
    {
        public static IServiceCollection AddMyOptions(this IServiceCollection services)
        {
            services.AddSingleton(typeof(IOptions<>), typeof(UnamedOptionsManager<>));
            services.AddSingleton(typeof(IOptionsMonitor<>), typeof(OptionsMonitor<>));
            services.AddScoped(typeof(IOptionsSnapshot<>), typeof(OptionsManager<>));
            services.AddTransient(typeof(IOptionsFactory<>), typeof(OptionsFactory<>));
            return services;
        }

        public static IServiceCollection MyConfigure<T>(this IServiceCollection services, Action<T> configureOptions) where T : class
            => services.MyConfigure(Options.DefaultName, configureOptions);

        public static IServiceCollection MyConfigure<T>(this IServiceCollection services, string? name, Action<T> configureOptions) where T : class
        {
            services.AddMyOptions();
            services.AddSingleton<IConfigureOptions<T>>(new ConfigureNamedOptions<T>(name, configureOptions));
            return services;
        }

        public static IServiceCollection MyConfigureAll<T>(this IServiceCollection services, Action<T> configureOptions) where T : class
            => services.MyConfigure(name: null, configureOptions: configureOptions);

        public static IServiceCollection PostConfigure<T>(this IServiceCollection services, Action<T> configureOptions) where T : class
            => services.PostConfigure(Options.DefaultName, configureOptions);


        public static IServiceCollection MyPostConfigure<T>(this IServiceCollection services, string? name, Action<T> configureOptions)
           where T : class
        {
            services.AddMyOptions();
            services.AddSingleton<IPostConfigureOptions<T>>(new PostConfigureOptions<T>(name, configureOptions));
            return services;
        }

        public static IServiceCollection MyPostConfigureAll<TOptions>(this IServiceCollection services, Action<TOptions> configureOptions) where TOptions : class
            => services.PostConfigure(name: null, configureOptions: configureOptions);

        public static IServiceCollection ConfigureOptions(this IServiceCollection services, Type configureType)
        {
            services.AddMyOptions();

            bool added = false;
            foreach (Type serviceType in FindConfigurationServices(configureType))
            {
                services.AddTransient(serviceType, configureType);
                added = true;
            }

            if (!added)
            {
                //ThrowNoConfigServices(configureType);
            }

            return services;
        }

        private static IEnumerable<Type> FindConfigurationServices(Type type)
        {
            foreach (Type t in GetInterfacesOnType(type))
            {
                if (t.IsGenericType)
                {
                    Type gtd = t.GetGenericTypeDefinition();
                    if (gtd == typeof(IConfigureOptions<>) ||
                        gtd == typeof(IPostConfigureOptions<>))
                    {
                        yield return t;
                    }
                }
            }

            // Extracted the suppression to a local function as trimmer currently doesn't handle suppressions
            // on iterator methods correctly.
            static Type[] GetInterfacesOnType(Type t)
                => t.GetInterfaces();
        }

        public static OptionsBuilder<TOptions> AddOptions<TOptions>(this IServiceCollection services) where TOptions : class
            => services.AddOptions<TOptions>(Options.DefaultName);

        public static OptionsBuilder<TOptions> AddOptions<TOptions>(this IServiceCollection services, string? name)
            where TOptions : class
        {
            services.AddMyOptions();
            return new OptionsBuilder<TOptions>(services, name);
        }
    }
}

标签:Options,name,options,public,services,class,Name
From: https://www.cnblogs.com/readafterme/p/18411974

相关文章

  • Why system logging "kernel: tcp_parse_options: Illegal window scaling value 15 >
    环境Linux问题在var/log/messages文件中发现以下日志。Oct621:01:05mplttaxsx101kernel:tcp_parse_options:Illegalwindowscalingvalue15>14received.Oct621:01:05mplttaxsx101kernel:tcp_parse_options:Illegalwindowscalingvalue15>14......
  • 再谈options
    场景部署服务过程中遇到了跨域问题,仅仅添加了跨域字段Access-Control-Allow-Origin,Access-Control-Allow-Methods,Access-Control-Allow-Headers还不行。Access-Control-Allow-Credentialstrue;Access-Control-Allow-Origin*;Access-Control-Allow-Headers'Content-Typ......
  • Android开发 - BitmapFactory 类解码图像文件并转换为 Bitmap 对象与 BitmapFactory.O
    BitmapFactory是什么BitmapFactory用于解码图像文件,并将它们转换为Bitmap对象。Bitmap是用来表示图像的基本类,它是一个位图的抽象表示。BitmapFactory提供了一组静态方法,这些方法可以用来将各种图像文件格式(如PNG、JPEG、WEBP等)解码成Bitmap对象BitmapFactory的好......
  • Android开发 - BleConnectOptions 类设置蓝牙连接选项解析
    BleConnectOptions是什么BleConnectOptions类是与蓝牙设备连接相关的一个配置类。它主要用于设置蓝牙连接的选项,确保与蓝牙设备的连接能够根据需求进行调整和优化。常用于配置蓝牙设备的连接参数,例如连接超时时间、是否自动连接等。这些配置可以帮助你更好地控制蓝牙连接过程,......
  • LeetCode 1359. Count All Valid Pickup and Delivery Options
    原题链接在这里:https://leetcode.com/problems/count-all-valid-pickup-and-delivery-options/description/题目:Given n orders,eachorderconsistsofapickupandadeliveryservice.Countallvalidpickup/deliverypossiblesequencessuchthatdelivery(i)isalw......
  • 深入解析Node.js中的fs.watch:options与listener详解
    在Node.js中,fs.watch方法是一个功能强大的文件系统监控工具,它允许我们对文件或目录进行实时监控,并在文件或目录发生变化时触发相应的操作。在使用fs.watch时,两个关键的部分是options对象和listener回调函数。本文将详细讲解这两个部分,帮助读者更好地理解和使用fs.watch。一......
  • OFtutorial02_commandLineArgumentsAndOptions
    OFtutorial2.CargList类如图包含很多函数,常用的addNote(输出字符串),noParallel(去掉基类中的并行选项),addBoolOption,addOption(增加选项)源码#include"fvCFD.H"#argc即argumentcount的缩写,保存程序运行时传递给主函数的参数个数;argv即argumentvector的缩写,保存程序运行......
  • ftrace的trace_options
    ftrace中的trace_options选项用于控制追踪数据的收集和显示方式。你可以通过/sys/kernel/debug/tracing/trace_options文件来设置这些选项。每个选项代表了不同的追踪行为或输出格式。以下是一些常见的trace_options选项及其含义:overwrite:含义:当启用此选项时,如果缓冲......
  • Selenium“没有提供‘moz:firefoxOptions.binary’功能,并且在命令行上没有设置二进制
    我一直在尝试将python脚本移植到我的wsl/bash编码中心中。我继续收到此错误:Traceback(mostrecentcalllast):File"/path/to/my/file.py",line20,in<module>driver=webdriver.Firefox(service=FirefoxService(GeckoDriverManager().install()))Fil......
  • 常用System.Text.Json的JsonSerializerOptions配置
    newJsonSerializerOptions{PropertyNamingPolicy=JsonNamingPolicy.CamelCase,//驼峰命名规则Encoder=JavaScriptEncoder.Create(UnicodeRanges.BasicLatin,//基础拉丁文字母UnicodeRanges.CjkUnifiedIdeographs,//中日韩统一的表意文字......