程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 為C# as 類型轉換及Assembly.LoadFrom埋坑!,

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

編輯:C#入門知識

為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。

2:as 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)

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

1:as 類型轉換:只檢測上下文中類型是否一致(或存在隱式轉換),若失敗返回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類型無法互轉,這麼多年終於遇上了,說明上的山多還是會見鬼的。

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

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved