為C# as 類型轉換及Assembly.LoadFrom埋坑!


背景:

不久前,我發布了一個調試工具:發布:.NET開發人員必備的可視化調試工具(你值的擁有)

效果是這樣的:

之后,有小部分用戶反映,工具用不了(沒反應或有異常)~~~

然后,建議小部分用戶換個電腦環境試試,有些就好了~~~

於是,我假定是VS環境下的 Microsoft.VisualStudio.DebuggerVisualizers.dll 的版本不一致引發的。

因此,一般我都建議用戶自己下載源碼,重新引用去編繹一下!!!

由於該工具一直在CSDN論壇的VB.NET版塊置頂着。

考慮到受眾多,中間還偷偷升級過幾回,解決了拋異常的問題,不過仍沒有從根本性解決~~~~

這兩天,有個叫子寒的同學,找上了我,希望我幫他解決這個問題。

我試着重新編繹了新版本發給他,都反饋木有效果。

只好讓他下載源碼,並在他電腦上進行遠程調試。

昨晚處理到深夜1點半,終於:把發現的兩個坑給埋了!!!

下面介紹下這兩個坑:

1:as 轉換的坑:

先看一段源碼,這是拿到反序列化的結果,轉Table,再綁定:

 protected override void Show(IDialogVisualizerService windowService, IVisualizerObjectProvider objectProvider)
        {
            MDataTable dt = objectProvider.GetObject() as MDataTable;
            FormCreate.BindTable(windowService, dt, null);
        }

在這段代碼中,調試的結果:

1:objectProvider.GetObject() 拿到的對象是MDataTable,GetType也返回的CYQ.Data.Table.MDataTable。

2as MDataTable 卻返回了null ?

咦?一個大大的問號在我面前,同樣的類型,怎么as不過去?

於是我把代碼改了一下:

MDataTable dt=(MDataTable)objectProvider.GetObject()

拋異常了:

************** 異常文本 **************
System.InvalidCastException: [A]CYQ.Data.Table.MDataTable 無法強制轉換為 [B]CYQ.Data.Table.MDataTable。
類型 A 源自“CYQ.Data, Version=5.7.5.5, Culture=neutral, PublicKeyToken=null”(在字節數組的上下文“LoadNeither”中)。
類型 B 源自“CYQ.Data, Version=5.7.5.5, Culture=neutral, PublicKeyToken=null”(在上下文“LoadFrom”中的“C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Packages\Debugger\Visualizers\CYQ.Data.dll”位置處)。 在 CYQ.Visualizer.MDataTableVisualizer.Show(IDialogVisualizerService windowService, IVisualizerObjectProvider objectProvider) 在 Microsoft.VisualStudio.DebuggerVisualizers.DebugViewerShim.ManagedShim.DelegatedHost.CreateViewer(IntPtr hwnd, HostServicesHelper hsh, SafeProxyWrapper proxy)

這個異常是什么等會再說,先補充知識點先:

1as 類型轉換:只檢測上下文中類型是否一致(或存在隱式轉換),若失敗返回null,不拋異常。

2:強制類型轉換:嘗試進行類型轉換,轉換失敗時,拋出異常。

好吧,第一個坑,相同的類型,沒有異常,埋的夠深!!!

AS叫了:這坑不能怪我,要怪就怪Assembly.LoadFrom,誰讓你們把我們分隔在不同的上下文中。

2:Assembly.LoadFrom 的坑

這里再貼一段詳細的異常信息:

mscorlib
    程序集版本:4.0.0.0
    Win32 版本:4.0.30319.36373 built by: FX452RTMLDR
    基本代碼:file:///C:/Windows/Microsoft.NET/Framework/v4.0.30319/mscorlib.dll
----------------------------------------
Microsoft.VisualStudio.Platform.AppDomainManager
    程序集版本:12.0.0.0
    Win32 版本:12.0.21005.1
    基本代碼:file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/Microsoft.VisualStudio.Platform.AppDomainManager/v4.0_12.0.0.0__b03f5f7f11d50a3a/Microsoft.VisualStudio.Platform.AppDomainManager.dll
----------------------------------------
System
    程序集版本:4.0.0.0
    Win32 版本:4.0.30319.36373 built by: FX452RTMLDR
    基本代碼:file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System/v4.0_4.0.0.0__b77a5c561934e089/System.dll
----------------------------------------
System.Xml
    程序集版本:4.0.0.0
    Win32 版本:4.0.30319.36373 built by: FX452RTMLDR
    基本代碼:file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Xml/v4.0_4.0.0.0__b77a5c561934e089/System.Xml.dll
----------------------------------------
System.Configuration
    程序集版本:4.0.0.0
    Win32 版本:4.0.30319.36373 built by: FX452RTMLDR
    基本代碼:file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Configuration/v4.0_4.0.0.0__b03f5f7f11d50a3a/System.Configuration.dll
----------------------------------------
System.Windows.Forms
    程序集版本:4.0.0.0
    Win32 版本:4.0.30319.36373 built by: FX452RTMLDR
    基本代碼:file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Windows.Forms/v4.0_4.0.0.0__b77a5c561934e089/System.Windows.Forms.dll
----------------------------------------
System.Drawing
    程序集版本:4.0.0.0
    Win32 版本:4.0.30319.36373 built by: FX452RTMLDR
    基本代碼:file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Drawing/v4.0_4.0.0.0__b03f5f7f11d50a3a/System.Drawing.dll
----------------------------------------
Microsoft.VisualStudio.DebuggerVisualizers
    程序集版本:12.0.0.0
    Win32 版本:12.0.21005.1
    基本代碼:file:///C:/Windows/assembly/GAC_MSIL/Microsoft.VisualStudio.DebuggerVisualizers/12.0.0.0__b03f5f7f11d50a3a/Microsoft.VisualStudio.DebuggerVisualizers.dll
----------------------------------------
CYQ.Visualizer
    程序集版本:2.0.0.5
    Win32 版本:2.0.0.5
    基本代碼:file:///C:/Program%20Files%20(x86)/Microsoft%20Visual%20Studio%2012.0/Common7/Packages/Debugger/Visualizers/CYQ.Visualizer.dll
----------------------------------------
CYQ.Data
    程序集版本:5.7.5.5
    Win32 版本:5.7.5.5
    基本代碼:file:///C:/Program%20Files%20(x86)/Microsoft%20Visual%20Studio%2012.0/Common7/Packages/Debugger/Visualizers/CYQ.Data.DLL
----------------------------------------
System.Data
    程序集版本:4.0.0.0
    Win32 版本:4.0.30319.36373 built by: FX452RTMLDR
    基本代碼:file:///C:/Windows/Microsoft.Net/assembly/GAC_32/System.Data/v4.0_4.0.0.0__b77a5c561934e089/System.Data.dll
----------------------------------------
System.Core
    程序集版本:4.0.0.0
    Win32 版本:4.0.30319.36373 built by: FX452RTMLDR
    基本代碼:file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Core/v4.0_4.0.0.0__b77a5c561934e089/System.Core.dll
----------------------------------------
CYQ.Data
    程序集版本:5.7.5.5
    Win32 版本:12.0.21005.1
    基本代碼:file:///C:/Windows/assembly/GAC_MSIL/Microsoft.VisualStudio.DebuggerVisualizers/12.0.0.0__b03f5f7f11d50a3a/Microsoft.VisualStudio.DebuggerVisualizers.dll
----------------------------------------
System.Numerics
    程序集版本:4.0.0.0
    Win32 版本:4.0.30319.36373 built by: FX452RTMLDR
    基本代碼:file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Numerics/v4.0_4.0.0.0__b77a5c561934e089/System.Numerics.dll
----------------------------------------
System.Transactions
    程序集版本:4.0.0.0
    Win32 版本:4.0.30319.36373 built by: FX452RTMLDR
    基本代碼:file:///C:/Windows/Microsoft.Net/assembly/GAC_32/System.Transactions/v4.0_4.0.0.0__b77a5c561934e089/System.Transactions.dll
----------------------------------------
System.EnterpriseServices
    程序集版本:4.0.0.0
    Win32 版本:4.0.30319.36373 built by: FX452RTMLDR
    基本代碼:file:///C:/Windows/Microsoft.Net/assembly/GAC_32/System.EnterpriseServices/v4.0_4.0.0.0__b03f5f7f11d50a3a/System.EnterpriseServices.dll
----------------------------------------
System.Windows.Forms.resources
    程序集版本:4.0.0.0
    Win32 版本:4.0.30319.34209 built by: FX452RTMGDR
    基本代碼:file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Windows.Forms.resources/v4.0_4.0.0.0_zh-Hans_b77a5c561934e089/System.Windows.Forms.resources.dll
----------------------------------------
************** 已加載的程序集 **************

 異常里核心的兩段:

CYQ.Visualizer
    程序集版本:2.0.0.5
    Win32 版本:2.0.0.5
    基本代碼:file:///C:/Program%20Files%20(x86)/Microsoft%20Visual%20Studio%2012.0/Common7/Packages/Debugger/Visualizers/CYQ.Visualizer.dll
----------------------------------------
CYQ.Data
    程序集版本:5.7.5.5
    Win32 版本:5.7.5.5
    基本代碼:file:///C:/Program%20Files%20(x86)/Microsoft%20Visual%20Studio%2012.0/Common7/Packages/Debugger/Visualizers/CYQ.Data.DLL

CYQ.Data
    程序集版本:5.7.5.5
    Win32 版本:12.0.21005.1
    基本代碼:file:///C:/Windows/assembly/GAC_MSIL/Microsoft.VisualStudio.DebuggerVisualizers/12.0.0.0__b03f5f7f11d50a3a/Microsoft.VisualStudio.DebuggerVisualizers.dll

從上面的異常錯誤信息中,第一眼看是要蒙B的,畢竟少見多怪啊~~~~

大概花了8分鍾,終於反應過來了,經過仔細的思考,可以發現:

1:CYQ.Data 被CYQ.Visualizer.dll加載是在同一目錄下。

2:被Microsoft.VisualStudio.DebuggerVisualizers.dll加載卻是在(上下文“LoadNeither”中,鬼知道這個LoadNeither是什么)。

於是,同一個dll被加載成兩個不同路徑,導致上下文環境不一樣,而不能互轉~~~~

為什么大部分正常,小部分環境會這么處理呢,目前無從知道,微軟也是愛造坑的~~~

好吧,坑已經知道了,接下來如何埋才是重點:

1:埋坑思維一:測試下Assembly.Load、Assembly.LoadFile、Assembly.LoadFrom

寫了幾段測試代碼:

 string filePath = AppDomain.CurrentDomain.BaseDirectory + "cyq\\CYQ.Data.dll";
            byte[] bytes = File.ReadAllBytes(filePath);
            Assembly ass = Assembly.Load(bytes);
            object o = ass.CreateInstance("CYQ.Data.Table.MDataTable");
 MDataTable dt = (MDataTable)o;

失敗!

 string filePath = AppDomain.CurrentDomain.BaseDirectory + "cyq\\CYQ.Data.dll";
 Assembly ass = Assembly.LoadFrom(filePath);
 Assembly.LoadFile(filePath);
...省略...

都失敗!!

測試這三個方法,主要是想看看有沒有啥本質的不一樣,特別是和強簽名合在一起后~~~

把dll加個強簽名試試~~~

仍失敗~~~~

看來,我想多了,不同的dll路徑加載的對象轉換這條路是不通的了~~~~

2:埋坑思維二:強簽名DLL,並注冊到GAC中

理論上來說:該方式100%是可行的,畢竟路徑的引用都是一致的。

方式也簡單:通過代碼加個注冊的命令也不是什么難事~~~~

還是思考有沒有其它更簡潔的方式!

3:埋坑思維三:找個穩定的中介

既然問題出現在序列化前的MDataTable和反序列化后的MDataTable在不同上下文的dll而導致的。

那就就找一種第三方中介了:MDataTable=>中介(序列化)=》中介(反序列化)=>MDataTable

不用動腦,就可以想到兩種:json或 DataTable。

於是代碼就動起來了:

序列化時,用DataTable

反序列化時:

打完收工,重新編繹,發給用戶測試,正常通過~

工具下載地址:

http://www.cnblogs.com/cyq1162/p/6027051.html

總結:

1:這么多年,第一次栽坑在as轉換上,也許是沒想到,也許是萬萬想不到。

2:不同的路徑加載的相同的dll類型無法互轉,這么多年終於遇上了,說明上的山多還是會見鬼的。

可既然版本號和簽名都一致,又認為簽名無法偽造,那為什么不呢?

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM