設計一下類似SpringIoC的註入工具~Lind.DI

来源:https://www.cnblogs.com/lori/archive/2019/04/12/10696640.html
-Advertisement-
Play Games

通過註解(特性)的方式進行對象的註冊與註入,方便,靈活! 本篇主要講如何去實現,下一篇主要講如何把它集成到mvc和api環境里,實現自動的註入! spring ioc工作的過程大致為,統一的註冊組件,攔截當前請求,統一的註入當前請求所需要的組件,事實上,說到這事,.net也完全可以實現這個功能和工作 ...


通過註解(特性)的方式進行對象的註冊與註入,方便,靈活!

  • 本篇主要講如何去實現,下一篇主要講如何把它集成到mvc和api環境里,實現自動的註入!

    spring ioc工作的過程大致為,統一的註冊組件,攔截當前請求,統一的註入當前請求所需要的組件,事實上,說到這事,.net也完全可以實現這個功能和工作方式,下來大叔來實現一下

  1. 定義組件註冊特性
  2. 定義組件生命周期
  3. 定義組件註入特性
  4. 定義Ioc工廠
  5. 使用靈活方便
  6. 將註入功能集成到mvc的攔截器里

定義組件註冊特性

定義在類身上

    /// <summary>
    /// 註冊組件特性.
    /// </summary>
    [AttributeUsage(AttributeTargets.Class)]
    public class ComponentAttribute : Attribute
    {
        public LifeCycle LifeCycle { get; set; } = LifeCycle.CurrentScope;

        public String Named { get; set; }
    }

定義組件生命周期

    /// <summary>
    /// 組件生命周期
    /// </summary>
    public enum LifeCycle
    {
        CurrentScope,
        CurrentRequest,
        Global,
    }

定義組件註入特性

定義在欄位上

    /// <summary>
    /// 註入一對象.
    /// </summary>
    [AttributeUsage(AttributeTargets.Field)]
    public class InjectionAttribute : Attribute
    {
        public string Named{get;set;}
    }

定義Ioc工廠

    /// <summary>
    /// DI工廠.
    /// </summary>
    public class DIFactory
    {

        static IContainer container;

        /// <summary>
        /// 手動註入.
        /// </summary>
        /// <returns>The resolve.</returns>
        /// <typeparam name="T">The 1st type parameter.</typeparam>
        public static T Resolve<T>()
        {
            if (container == null)
                throw new ArgumentException("please run DIFactory.Init().");
            return container.Resolve<T>();
        }

        /// <summary>
        /// 手動註入.
        /// </summary>
        /// <returns>The by named.</returns>
        /// <param name="named">Named.</param>
        /// <typeparam name="T">The 1st type parameter.</typeparam>
        public static T ResolveByNamed<T>(string named)
        {
            if (container == null)
                throw new ArgumentException("please run DIFactory.Init().");
            return container.ResolveNamed<T>(named);
        }


    /// <summary>
        /// 把對象里的Inject特性的對象註入.
        /// web環境下,應該使用filter攔截器將當前控制器傳傳InjectFromObject去註入它.
        /// </summary>
        /// <param name="obj">Object.</param>
        public static void InjectFromObject(object obj)
        {
            if (obj.GetType().IsClass && obj.GetType() != typeof(string))
                foreach (var field in obj.GetType().GetFields(
                    BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public))
                {
                    if (field.GetCustomAttributes(false).Select(i => i.GetType())
                    .Contains(typeof(InjectionAttribute)))
                    {
                        InjectionAttribute inject = (InjectionAttribute)field.GetCustomAttributes(false).FirstOrDefault(i => i.GetType() == typeof(InjectionAttribute));
                        if (inject != null && !String.IsNullOrWhiteSpace(inject.Named))
                        {
                            field.SetValue(obj, container.ResolveNamed(inject.Named, field.FieldType));
                        }
                        else
                        {
                            field.SetValue(obj, container.Resolve(field.FieldType));
                        }
                        //遞歸處理它的內部欄位
                        InjectFromObject(field.GetValue(obj));
                    }

                }
        }

        /// <summary>
        /// 初始化.
        /// </summary>
        public static void Init()
        {
            var builder = new ContainerBuilder();
            var arr = AppDomain.CurrentDomain.GetAssemblies().Where(
                 x => !x.FullName.StartsWith("Dapper")
                 && !x.FullName.StartsWith("System")
                 && !x.FullName.StartsWith("AspNet")
                 && !x.FullName.StartsWith("Microsoft"))
                 .SelectMany(x => x.DefinedTypes)
                 .Where(i => i.IsPublic && i.IsClass)
                 .ToList();
            foreach (var type in arr)
            {
                try
                {
                    if (type.GetCustomAttributes(false).Select(i => i.GetType()).Contains(typeof(ComponentAttribute)))
                    {
                        ComponentAttribute componentAttribute = (ComponentAttribute)type.GetCustomAttributes(false).FirstOrDefault(o => o.GetType() == typeof(ComponentAttribute));

                        if (type.GetInterfaces() != null && type.GetInterfaces().Any())
                        {
                            type.GetInterfaces().ToList().ForEach(o =>
                            {
                                registor(builder, type, o, componentAttribute);

                            });
                        }
                        else
                        {
                            registor(builder, type, type, componentAttribute);
                        }
                    }
                }
                catch (Exception)
                {
                    throw new Exception($"Lind.DI init {type.Name} error.");
                }
            }
            container = builder.Build();
        }

        /// <summary>
        /// 註冊組件.
        /// </summary>
        /// <param name="builder">Builder.</param>
        /// <param name="typeImpl">Type impl.</param>
        /// <param name="type">Type.</param>
        /// <param name="componentAttribute">Component attribute.</param>
        static void registor(ContainerBuilder builder, Type typeImpl, Type type, ComponentAttribute componentAttribute)
        {
            if (componentAttribute.LifeCycle == LifeCycle.Global)
            {
                if (componentAttribute.Named != null)
                    builder.RegisterType(typeImpl).Named(componentAttribute.Named, type).SingleInstance();
                else
                    builder.RegisterType(typeImpl).As(type).SingleInstance();
            }
            else if (componentAttribute.LifeCycle == LifeCycle.CurrentScope)
            {
                if (componentAttribute.Named != null)
                    builder.RegisterType(typeImpl).Named(componentAttribute.Named, type).InstancePerLifetimeScope();
                else
                    builder.RegisterType(typeImpl).As(type).InstancePerLifetimeScope();
            }
            else
            {
                if (componentAttribute.Named != null)
                    builder.RegisterType(typeImpl).Named(componentAttribute.Named, type).InstancePerRequest();
                else
                    builder.RegisterType(typeImpl).As(type).InstancePerRequest();
            }
        }
    }

使用靈活方便

支持對象與對象之間的依賴

   [Component(Named="RunPeople")]
    public class RunPeople : IRun
    {
        public void Do()
        {
            System.Console.WriteLine("人類跑起來!");
        }
    }
    [Component]
    public class Fly
    {
        [Injection(Named="RunPeople")]
        Run run;
        public void step1()
        {
            run.Do();
            System.Console.WriteLine("飛行第一步!");
        }
    }

使用方式,程式入口先初始化DIFactory.Init();

       [Injection]
        Fly flyObj;
        void print(){
            DIFactory.Init();
            DIFactory.InjectFromObject(this);
            flyObj.step1();
        }
        static void Main(string[] args)
        {
            DIFactory.Init();
            System.Console.WriteLine("Hello World!");
            new Program().print();
        }

結果

Hello World!
人類跑起來!
飛行第一步!

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 安裝步驟:vs2010 -> vs2010sp1 -> AspNetMVC3Setup -> AspNetMVC3Setup_CHS -> AspNetMVC3ToolsUpdateSetup -> AspNetMVC3ToolsUpdateSetup_CHS ASP.NET MVC 3和VS工具更 ...
  • 今天我們來說下如何在windows下使用docker運行.net core,既然是docker,那麼我們首先得在windows上安裝docker。 在Windows安裝 docker 有兩種選擇 :1、docker for windows2、docker toolbox 區別:docker for ...
  • yyyyyyyyyyyyyyyyyyyyyyy yyyyyyyyyyyyyyyyyyyyyyy ...
  • 使用 ASP.NET Core MVC 創建 Web API 使用 ASP.NET Core MVC 創建 Web API(一) 使用 ASP.NET Core MVC 創建 Web API(二) 十、添加 GetBookItem 方法 1) 在Visual Studio 2017中的“解決方案資源 ...
  • 索引: 目錄索引 一.API 列表 1.Set<M, F>(Expression<Func<M, F>> propertyFunc, F newVal) 如: .Set(it => it.BodyMeasureProperty, "{xxx:yyy,mmm:nnn,zzz:aaa}") 用於 單表 ...
  • 今天自己開發了一個訂機票的微信公眾號,功能基本已經完成,然後想部署到伺服器實際測試下。結果部署上去出現各種問題。先安裝asp.net core模塊,然後發現資料庫並不像在開發時一樣,執行ef的命令行語句就可以了。可以到輸出目錄找到對應的sql語句,到伺服器上執行一下。 後來部署上去以後,發現很多對應... ...
  • 轉自:https://blog.csdn.net/jie_liang/article/details/77340905 用以記錄: 在sql查詢中為了提高查詢效率,我們常常會採取一些措施對查詢語句進行sql優化,下麵總結的一些方法,有需要的可以參考參考。 1.對查詢進行優化,應儘量避免全表掃描,首先 ...
  • //通過ClassName獲取div,使用setAttribute設置div禁止點擊 pointer-events: none;是css3新出現的屬性,意思就是禁止滑鼠點擊事件,當元素中有這一屬性時,鏈接、點擊事件統統失效 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...