日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

【C#|.NET】从控制反转(依赖注入)想到事件注入 (非AOP)

發(fā)布時(shí)間:2025/6/15 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【C#|.NET】从控制反转(依赖注入)想到事件注入 (非AOP) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前文

事件注入的想法是由依賴注入所聯(lián)想到

依賴注入不算什么吸引人的話題?本篇就不詳說(shuō)了?不過(guò)有閑暇時(shí)間的機(jī)會(huì)不妨按照自己的興趣去摸索、研究一些東西,也是一種樂(lè)子。

在抓蟲系列里簡(jiǎn)單的描述一下依賴注入在項(xiàng)目中的應(yīng)用場(chǎng)景抓蟲(五) 淺談依賴注入與控制反轉(zhuǎn)

關(guān)于依賴注入推薦T2噬菌體同學(xué)的一篇文章 依賴注入那些事兒

關(guān)于事件注入已添加進(jìn)我的設(shè)計(jì)模式 【系列索引】結(jié)合項(xiàng)目實(shí)例 回顧傳統(tǒng)設(shè)計(jì)模式 打造屬于自己的模式類系列


?概要

所謂事件注入是我一時(shí)興起隨便杜撰的詞,其思想借鑒依賴注入。當(dāng)然看到這個(gè)詞很多同學(xué)會(huì)想到AOP,這里先不置可否。

依賴注入(Dependency Injection),是這樣一個(gè)過(guò)程:由于某客戶類只依賴于服務(wù)類的一個(gè)接口,而不依賴于具體服務(wù)類,所以客戶類只定義一個(gè)注入點(diǎn)。在程序運(yùn)行過(guò)程中,客戶類不直接實(shí)例化具體服務(wù)類實(shí)例,而是客戶類的運(yùn)行上下文環(huán)境或?qū)iT組件負(fù)責(zé)實(shí)例化服務(wù)類,然后將其注入到客戶類中,保證客戶類的正常運(yùn)行。

也就是說(shuō)依賴注入在我們的項(xiàng)目場(chǎng)景中充當(dāng)一個(gè)解耦的角色。在項(xiàng)目結(jié)構(gòu)中它可以解耦出一個(gè)模塊、一個(gè)服務(wù)。T2噬菌體同學(xué)在他的博文中描述了一個(gè)游戲打怪的例子來(lái)解釋依賴注入的作用。那么我們同樣用打怪的例子來(lái)闡述下事件注入的場(chǎng)景。


?詳解

關(guān)于原型的設(shè)計(jì)可以參考T2同學(xué)對(duì)游戲打怪的描述,我這里直接略過(guò)看效果圖

下面我們撇開T2同學(xué)對(duì)依賴注入場(chǎng)景的設(shè)計(jì)。假設(shè)目前這個(gè)demo就是可行的。但是隨著游戲版本的更新,招式越來(lái)越多,效果越來(lái)越絢,規(guī)則越來(lái)越多。T2同學(xué)用依賴注入解決的重點(diǎn)是將Role和武器之間的依賴,封裝算法簇,讓它們之間可以互相替換,讓算法的變化獨(dú)立于使用算法的客戶類。

那么浮現(xiàn)問(wèn)題點(diǎn),如果我要更新的并不是武器等因素,而是對(duì)流程的更新。例如玩dota的同學(xué)都知道,一個(gè)英雄他的技能前后搖擺的時(shí)間也是很重要的因素,好吧,我們給游戲添加技能前搖的設(shè)置,砍完怪的我還得獲得金幣,嗯,再添加一下攻擊后獲得金幣的內(nèi)容。如何符合我們的OCP原則呢。于是,我們引入事件注入的概念。

首先我們來(lái)定義我們所需要的行為

/// <summary>/// 攻擊前事件/// </summary>public static event EventHandler<EventArgs> BeforeAttackEvent;protected virtual void BeforeAttack(EventArgs e){EventHandler<EventArgs> tmp = BeforeAttackEvent;if (tmp != null)tmp(this, e);}/// <summary>/// 攻擊后事件/// </summary>public static event EventHandler<GameEventArgs> AttackedEvent;protected virtual void OnAttacked(GameEventArgs e){EventHandler<GameEventArgs> tmp = AttackedEvent;if (tmp != null)tmp(this, e);}

?這里定義的僅僅是事件的句柄,如果在這里就實(shí)現(xiàn)我們事件的實(shí)體也就違背了我們ocp的原則以及事件注入的概念。

這里要提出說(shuō)明的EventArgs 是包含事件數(shù)據(jù)的類的基類,如果說(shuō)我們需要對(duì)注入的事件進(jìn)行額外的信息處理,例如我需要獲得金幣,那么金幣這個(gè)屬性需要在事件數(shù)據(jù)中說(shuō)明

例如上述的攻擊后事件

/// <summary>/// 注入事件元素/// </summary>public class GameEventArgs :EventArgs{public GameEventArgs(): this(0){}public int Coin {get;set;}public GameEventArgs(int coin){Coin = coin;}}

?事件的框架有了,我們便在現(xiàn)有程序中找尋合適的注入點(diǎn)。這里我選擇的是攻擊前后

/// <summary> /// 攻擊怪物 /// </summary> /// <param name="monster">被攻擊的怪物</param> public void Attack(Monster monster){BeforeAttack(EventArgs.Empty);if (monster.HP <= 0){Console.WriteLine("此怪物已死");return;}if ("WoodSword" == WeaponTag){monster.HP -= 20;if (monster.HP <= 0){Console.WriteLine("攻擊成功!怪物" + monster.Name + "已死亡");}else { Console.WriteLine("攻擊成功!怪物" + monster.Name + "損失20HP"); }}else if ("IronSword" == WeaponTag){monster.HP -= 50; if (monster.HP <= 0){Console.WriteLine("攻擊成功!怪物" + monster.Name + "已死亡");}else{Console.WriteLine("攻擊成功!怪物" + monster.Name + "損失50HP");}}else if ("MagicSword" == WeaponTag){Int32 loss = (_random.NextDouble() < 0.5) ? 100 : 200;monster.HP -= loss;if (200 == loss){Console.WriteLine("出現(xiàn)暴擊!!!");}if (monster.HP <= 0){Console.WriteLine("攻擊成功!怪物" + monster.Name + "已死亡");}else{Console.WriteLine("攻擊成功!怪物" + monster.Name + "損失" + loss + "HP");}}else{Console.WriteLine("角色手里沒(méi)有武器,無(wú)法攻擊!");}var e =new GameEventArgs();OnAttacked(e);}

?這些設(shè)計(jì)完成之后,我們需要的就是設(shè)計(jì)來(lái)注入些什么事件。

[Extension("游戲規(guī)則_攻擊前", "1.0.0.0", "熬夜的蟲子")]public class GameRule{public GameRule(){Role.BeforeAttackEvent += BeforeAttack;}void BeforeAttack(object sender, EventArgs e){Console.WriteLine("技能前搖 扭動(dòng)身體..."); }}

?

[Extension("游戲規(guī)則_攻擊后", "1.0.0.0", "熬夜的蟲子")]public class GameRule2{private readonly Random _random = new Random();public GameRule2(){Role.AttackedEvent += Attacked;}void Attacked(object sender, EventArgs e){var currentrole = sender as Role;int addcoin = _random.Next(1, 10);if (currentrole != null){currentrole.Coin += addcoin;Console.WriteLine("本次攻擊獲得了..." + addcoin.ToString() + "個(gè)金幣,當(dāng)前金幣為" + currentrole.Coin+"個(gè)");}}}

?事件定義完成后,我們接下來(lái)的步驟就是如何來(lái)注入到我們現(xiàn)有的框架中。

老道的同學(xué)可以發(fā)現(xiàn)在事件定義的過(guò)程中,我用了擴(kuò)展屬性。沒(méi)錯(cuò),這個(gè)屬性就是實(shí)現(xiàn)注入環(huán)節(jié)的樞紐所在。

/// <summary>/// 事件注入實(shí)現(xiàn)/// </summary>[AttributeUsage(AttributeTargets.Class)]public class ExtensionAttribute : Attribute{public ExtensionAttribute(string description, string version, string author){_Description = description;_Version = version;_Author = author;}private readonly string _Description;public string Description{get { return _Description; }}private readonly string _Version;public string Version{get { return _Version; }}private readonly string _Author;public string Author{get { return _Author; }}}

?如果想更深入的同學(xué)可以在設(shè)計(jì)一個(gè)事件注入管理類,添加一些是否可用,過(guò)期時(shí)間,版本,描述等等信息來(lái)管理注入事件。例如當(dāng)管理類信息入庫(kù),每次注入前check管理類的信息。這樣可以可視化并更方便管理注入的事件。

我們回到注入實(shí)現(xiàn)這個(gè)話題上來(lái),如何利用這個(gè)擴(kuò)展屬性,通過(guò)反射。

var di = new System.IO.DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory);foreach (var item in di.GetFiles("*.dll", System.IO.SearchOption.TopDirectoryOnly)){System.Reflection.Assembly assembly = System.Reflection.Assembly.LoadFrom(item.FullName);Type[] types = assembly.GetTypes();foreach (Type type in types){object[] attributes = type.GetCustomAttributes(typeof(Extension.ExtensionAttribute), false);foreach (object attribute in attributes){assembly.CreateInstance(type.FullName);}}}

?上面的程序更具我們定義的擴(kuò)展屬性找到相關(guān)的注入事件方法類型,并生成實(shí)例。到此,一個(gè)簡(jiǎn)單的注入流程就已經(jīng)OK了。

我們來(lái)看一下效果。

?注入事件的組件與源程序分開,源程序不依賴注入事件組件,可以任意的定義多個(gè)同類注入事件,將組件放入程序指定的目錄即可。

例如我們?cè)傩陆ㄒ粋€(gè)注入事件組件

[Extension("游戲規(guī)則_攻擊后", "1.0.0.0", "熬夜的蟲子")]public class GameRule{public GameRule(){Role.AttackedEvent += Attacked;}void Attacked(object sender, EventArgs e){Console.WriteLine("技能后擺 O(∩_∩)O哈哈哈~...");}}

配置完成后,看下效果?


?本篇到此 希望對(duì)大家有幫助

轉(zhuǎn)載于:https://www.cnblogs.com/dubing/archive/2011/12/21/2295895.html

總結(jié)

以上是生活随笔為你收集整理的【C#|.NET】从控制反转(依赖注入)想到事件注入 (非AOP)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。