国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發(fā)設(shè)計 > 正文

第三方組件引用另一個第三方組件的悲劇

2019-11-14 16:40:09
字體:
供稿:網(wǎng)友

首先我先聲明,我的摘要是故意這樣寫的,如果你是因為看了摘要才進來的,請讓我大笑三聲:哈哈哈~~

不過既然你已經(jīng)進來了,不妨繼續(xù)往下看看~~

事件背景

話說最近換工作了,剛接手的項目的項目中遇到一個棘手的事情;一個第三方組件中使用了老版的log4net(1.2.10),另一個第三方組件中使用了新版的log4net(1.2.13)

這下問題來了

當我自己的項目中需要同時使用這2個第三方組件的時候,他們各自引用的log4net版本是不一致的

所以,不管我引用的是哪個版本的log4net,最終的效果是另一個組件初始化的時候?qū)伋霎惓?/span>

如下圖:

由于2個都是非開源的項目,所以無法重新編譯,好在其中一個組件是有技術(shù)支持的,所以聯(lián)系了他們的服務(wù)人員

經(jīng)過一些交涉,問題算是初步解決了

服務(wù)還是非常好的!!贊一個!!!!

不過從最后一句話可以看出,其實最終的原因,還是出在設(shè)計上!!

為什么一定要耦合log4net?

沒錯~我承認log4net確實是一款不錯的log組件,但是即使是不錯也不是必要的,不可或缺的!

想想JQuery,多么好的一個js組件,依然有很多公司沒有使用jquery,依賴于jquery的往往被稱為jquery插件,因為一旦jquery失效了(或沒引用),你的組件就無法使用了

所以在開發(fā)自己的組件的時候,就需要定位清楚!

這套組件到底是log4net的插件,還是功能獨立的???是否沒有了log4net,組件就無法工作了??

即使它工作再強大,也是輔助而已,并不是不可或缺的!

第三方組件的日志設(shè)計

假設(shè)現(xiàn)在有一個第三方組件,使用上沒有難度

static void Main(string[] args){    //初始化第三方控件(讀取配置文件等操作)    SendMessage sm = new SendMessage();    //設(shè)置參數(shù)    sm.Arg1 = "1";    sm.Arg2 = "2";    sm.Arg3 = "3";    sm.Arg4 = "4";                //執(zhí)行方法,獲取返回值    var result = sm.Send();    Console.WriteLine(result);}

但是如果SendMessage是這樣寫的

public class SendMessage{    ILog Log;    public SendMessage()    {        Log = log4net.LogManager.GetLogger(typeof(SendMessage));        Log.Info("初始化完成");    }    public string Arg1 { get; set; }    public string Arg2 { get; set; }    public string Arg3 { get; set; }    public string Arg4 { get; set; }    public string Send()    {        try        {            Log.Info("發(fā)送請求");            Log.InfoFormat("參數(shù)1={0};2={1};3={2};4={3};", Arg1, Arg2, Arg3, Arg4);            string result = null;            //.....            Log.Info("返回值是:" + result);            return result;        }        catch (Exception ex)        {            Log.Error("出現(xiàn)異常",ex);            throw;        }    }}

就有可能會出現(xiàn)我第一節(jié)中說的情況

并且,這個SendMessage和log4net是高度耦合的!

更換自己的接口

這個是最容易實現(xiàn)的

我們先把log4net拋棄~然后自己聲明一個ILog接口

public interface ILog{    void Info(string message);    void Debug(string message);    void Warn(string message);    void Error(string caption, Exception ex);}

然后替換到SendMessage中

public class SendMessage{    ILog Log;    public SendMessage(ILog log)    {        Log = log;        if (log != null)        {            Log.Info("初始化完成");        }    }    public SendMessage()    {    }    public string Arg1 { get; set; }    public string Arg2 { get; set; }    public string Arg3 { get; set; }    public string Arg4 { get; set; }    public string Send()    {        try        {            if (Log != null)            {                Log.Info("發(fā)送請求");                Log.Info(string.Format("參數(shù)1={0};2={1};3={2};4={3};", Arg1, Arg2, Arg3, Arg4));            }            string result = null;            //.....            if (Log != null)            {                Log.Info("返回值是:" + result);            }            return result;        }        catch (Exception ex)        {            if (Log != null)            {                Log.Error("出現(xiàn)異常", ex);            }            throw;        }    }}

這樣非常簡單的就把日志的操作權(quán)交出去了,讓調(diào)用者自己去考慮怎樣完成

 

嗯,其實我只想調(diào)試一下,并不想持久化日志信息,所以我可以這么干

static void Main(string[] args){    //初始化第三方控件(讀取配置文件等操作)    SendMessage sm = new SendMessage(new MyLog());    //設(shè)置參數(shù)    sm.Arg1 = "1";    sm.Arg2 = "2";    sm.Arg3 = "3";    sm.Arg4 = "4";    //執(zhí)行方法,獲取返回值    var result = sm.Send();    Console.WriteLine(result);}class MyLog : ILog{    public void Info(string message)    {        Console.WriteLine("info:" + message);    }    public void Debug(string message)    {        Console.WriteLine("debug:" + message);    }    public void Warn(string message)    {        Console.WriteLine("warn:" + message);    }    public void Error(string caption, Exception ex)    {        Console.WriteLine("error:" + caption);        Console.WriteLine("error:" + ex.ToString());    }}

如果使用者希望繼續(xù)使用log4net當然也是沒有問題的

class MyLog : ILog{    log4net.ILog Log;    public MyLog()    {        Log = log4net.LogManager.GetLogger(typeof(MyLog));    }    public void Info(string message)    {        Log.Info(message);    }    public void Debug(string message)    {        Log.Debug(message);    }    public void Warn(string message)    {        Log.Warn(message);    }    public void Error(string caption, Exception ex)    {        Log.WriteLine(caption, ex);    }}

其實這個時候已經(jīng)很好的和log4net解耦!!

 

到這里,如果不想了解系統(tǒng)的Trace和Debug類的,就可以直接跳到結(jié)束語

使用系統(tǒng)對象(接口/抽象類)

話說回來,我是一個很懶的人,能少定義一個類,盡量少定義一個類

所以我可以不用定義ILog接口,因為系統(tǒng)已經(jīng)為我們提供的相應(yīng)的對象TraceListener該有的方法都有了

所以我直接這么干!

public class SendMessage{    TraceListener Log;    public SendMessage(TraceListener log)    {        Log = log;        if (log != null)        {            Log.Write("初始化完成");        }    }    public SendMessage()    {    }    public string Arg1 { get; set; }    public string Arg2 { get; set; }    public string Arg3 { get; set; }    public string Arg4 { get; set; }    public string Send()    {        try        {            if (Log != null)            {                Log.Write("發(fā)送請求");                Log.Write(string.Format("參數(shù)1={0};2={1};3={2};4={3};", Arg1, Arg2, Arg3, Arg4));            }            string result = null;            //.....            if (Log != null)            {                Log.Write( "返回值是:" + result);            }            return result;        }        catch (Exception ex)        {            if (Log != null)            {                Log.Write(ex, "出現(xiàn)異常");            }            throw;        }    }}

現(xiàn)在我已經(jīng)把ILog這個接口給干掉了

所以用戶在使用組件的時候,就需要繼承TraceListener了

class MyLog : TraceListener{    //必須實現(xiàn)    public override void Write(string message)    {        this.WriteLine("info:" + message);    }    //必須實現(xiàn)    public override void WriteLine(string message)    {        Console.WriteLine(message);    }    //可重寫,可不寫    public override void Write(object o, string category)    {        if (o is Exception)        {            Console.WriteLine("error:" + category);            Console.WriteLine("error:" + o.ToString());        }        else        {            this.WriteLine(category + ":" + o.ToString());        }    }}

其中只有void Write(string message)和void WriteLine(string message)是必須實現(xiàn)的

其他都可以選擇重寫

比如,當你沒有重寫Write(object o, string category)的時候,就會調(diào)用Write(string message)方法

封裝方法

剛才在SendMessage中出現(xiàn)了很多

if (Log != null){    Log.Write(message);}

而且這還只是一個演示的項目,真實的項目中會更多這樣的東西,所以必須封裝方法

        public string Send()        {            try            {                Info("發(fā)送請求");                Info(string.Format("參數(shù)1={0};2={1};3={2};4={3};", Arg1, Arg2, Arg3, Arg4));                string result = null;                //.....                Info("返回值是:" + result);                return result;            }            catch (Exception ex)            {                Error("出現(xiàn)異常", ex);                throw;            }        }        PRivate void Info(string message)        {            if (Log != null)            {                Log.Write(message);            }        }        private void Error(string caption, Exception ex)        {            if (Log != null)            {                Log.Write(ex, caption);            }        }

使用系統(tǒng)的方法

之前說了,我是一個很懶的人,能少寫一個方法,就要少寫一個方法

所以,我其實不用封裝方法,直接拿系統(tǒng)方法用就好了,而且連構(gòu)造函數(shù)都省了!

public class SendMessage{    public SendMessage()    {        Trace.WriteLine("初始化完成");    }    public string Arg1 { get; set; }    public string Arg2 { get; set; }    public string Arg3 { get; set; }    public string Arg4 { get; set; }    public string Send()    {        try        {            Trace.WriteLine("發(fā)送請求");            Trace.WriteLine(string.Format("參數(shù)1={0};2={1};3={2};4={3};", Arg1, Arg2, Arg3, Arg4));            string result = null;            //.....            Trace.WriteLine("返回值是:" + result);            return result;        }        catch (Exception ex)        {            //3種方式都可以,但是只有 WriteLine 可以接受object的參數(shù),這點比較2            //Trace.TraceError("出現(xiàn)異常:" + ex.ToString());            //Trace.Fail("出現(xiàn)異常:" + ex.Message, ex.StackTrace);            Trace.WriteLine(ex, "出現(xiàn)異常:");            throw;        }    }}

既然改了構(gòu)造函數(shù),那么用戶使用的時候也需要修改了

 

        static void Main(string[] args)        {            //設(shè)置輸出日志組件            Trace.Listeners.Add(new MyLog());            //初始化第三方控件(讀取配置文件等操作)            SendMessage sm = new SendMessage();            //設(shè)置參數(shù)            sm.Arg1 = "1";            sm.Arg2 = "2";            sm.Arg3 = "3";            sm.Arg4 = "4";            //執(zhí)行方法,獲取返回值            var result = sm.Send();            Console.WriteLine(result);        }
class MyLog : TraceListener{    //必須實現(xiàn)    public override void Write(string message)    {        this.WriteLine("info:" + message);    }    //必須實現(xiàn)    public override void WriteLine(string message)    {        Console.WriteLine(message);    }    //可重寫,可不寫    public override void Write(object o, string category)    {        if (o is Exception)        {            Console.WriteLine("error:" + category);            Console.WriteLine("error:" + o.ToString());        }        else        {            this.WriteLine(category + ":" + o.ToString());        }    }}
MyLog依然不變

效果如圖

 

關(guān)于Trace可以參考文章(利用C#自帶組件強壯程序日志)

結(jié)束語

寫這篇文章最想要表達的內(nèi)容是:非必要的情況下,第三方組件不應(yīng)該耦合其他第三方組件

這樣的做法就像是在綁架用戶:你用的我的組件,就必須使用xxx,否則我的組件就無法使用

除非你做的是"插件"形式的組件,所以為什么我所有的組件都是開源的,我更希望大家在使用的時候直接將源碼打包的程序中,而不是引用dll,這樣會給你的用戶帶來困擾

這篇文章第二點想做的,就是為之前的文章(利用C#自帶組件強壯程序日志)正名,不知道這樣一番解釋之后,有多少人明白了微軟的Trace模塊,只是一個接口,并不是日志組件

最后我想說的,我并沒有說log4net不好,也沒有提倡大家不使用log4net,只是我希望在使用log4net(還有其他輔助類的第三方組件)的時候

盡可能的對其進行解耦,不要過于依賴(直接引用)

避免一個輔助功能失效(或錯誤),造成整個系統(tǒng)崩潰

 

引用第三方組件的時候也要注意,盡量使其在一個項目中被引用,然后使用對象或接口進行二次封裝

避免一個組件在所有項目中都存在引用關(guān)系,一樣會造成上面說的一個功能失效(或錯誤),造成整個系統(tǒng)崩潰


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 张家港市| 榆社县| 西乌珠穆沁旗| 鲜城| 宜川县| 平阴县| 铁岭县| 房产| 宁远县| 新化县| 兖州市| 九寨沟县| 资阳市| 河南省| 绥滨县| 体育| 郎溪县| 高雄县| 即墨市| 来宾市| 焉耆| 砚山县| 塘沽区| 绥棱县| 禹城市| 台南市| 延边| 都江堰市| 丁青县| 武安市| 武功县| 竹山县| 扎赉特旗| 绥滨县| 渑池县| 寻甸| 珲春市| 安丘市| 苗栗县| 安丘市| 视频|