已知,子類B繼承自父類A,但是在代碼運行時,B類強制轉(zhuǎn)換為A類,卻報代碼轉(zhuǎn)換異常。
很奇怪的問題吧,不過這個也是難得機會,去研究C#運行的底層原理。
下面是報錯的代碼片段。
string className = _shapeReflectMap[typeName].ClassName;
Assembly assem = _shapeReflectMap[typeName].Assem;
Object obj = assem.CreateInstance(className); // 在dll程序集中 通過className實例化獲取子類
Type type1 = obj.GetType().BaseType; // 獲取父類類型
Type type2 = typeof(Shape);
Assembly assembly1 = type1.Assembly;
Assembly assembly2 = type2.Assembly;
string codeBase1 = assembly1.CodeBase;
string codeBase2 = assembly2.CodeBase;
try
{
shape = (Shape)obj;
}
catch (Exception e)
{
throw new Exception("反射創(chuàng)建Shape失敗"
+ "\n類型直接比較: " + (type1 == type2)
+ "\n程序集直接比較: " + (assembly1 == assembly2)
+ "\n類型全名比較: " + (type1.FullName == type2.FullName) + ": " + type1.FullName + " " + type2.FullName
+ "\n程序集全名比較: " + (assembly1.FullName == assembly2.FullName) + ": " + assembly1.FullName + " " + assembly2.FullName
+ "\ncodeBase1: " + codeBase1
+ "\ncodeBase2: " + codeBase2
+ "\n程序集路徑比較: " + (codeBase1 == codeBase2)
+ "\ncodeBase1.hash: " + codeBase1.GetHashCode()
+ "\ncodeBase2.hash: " + codeBase2.GetHashCode()
+ "\n", e);
}
下面是報錯結(jié)果(其中的敏感字符串被替換成了xxx):
System.Exception: 反射創(chuàng)建Shape失敗
類型直接比較: False
程序集直接比較: False
類型全名比較: True: xxx.WpfPlugin.Shape xxx.WpfPlugin.Shape
程序集全名比較: True: xxx.WpfPlugin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null xxx.WpfPlugin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
codeBase1: file:///D:/project/XXX/xxx.xxxClient.UI/xxx.xxxClient.UI/bin/Debug/Plugins/xxx.WpfPlugin.dll
codeBase2: file:///D:/project/XXX/xxx.xxxClient.UI/xxx.xxxClient.UI/bin/Debug/Plugins/xxx.WpfPlugin.dll
程序集路徑比較: True
codeBase1.hash: -336973287
codeBase2.hash: -336973287
---> System.InvalidCastException: 無法將類型為“xxx.WpfPlugin.Shapes.ImageButton”的對象強制轉(zhuǎn)換為類型“xxx.WpfPlugin.Shape”。
在 xxx.WpfPlugin.ctlUI.LoadXml(String xmlPath) 位置 D:\project\XXX\dll\PluginsSources\xxx.WpfPlugin\ctlUI.cs:行號 107
--- 內(nèi)部異常堆棧跟蹤的結(jié)尾 ---
在 xxx.WpfPlugin.ctlUI.LoadXml(String xmlPath) 位置 D:\project\XXX\dll\PluginsSources\xxx.WpfPlugin\ctlUI.cs:行號 111
在 xxx.WpfPlugin.ctlUI.DisplayInit() 位置 D:\project\XXX\dll\PluginsSources\xxx.WpfPlugin\ctlUI.cs:行號 177
通過上面的代碼可以看出,從子類中獲取的父類type,和父類直接獲取的type是完全一樣的,命名空間,類名稱,程序集和對應的dll文件,均相同。但是通過==
判斷,其在內(nèi)存中并非同一個對象。
經(jīng)過排查,發(fā)現(xiàn)代碼中對該dll加載了兩次,獲得了兩個程序集,而子類和父類分別來自不同的程序集,導致了無法進行類型轉(zhuǎn)換。在修復該dll加載邏輯后問題便得到了解決。
可以推測出,C#判斷兩個類是否完全相同,除了看命名空間和類名以外,主要是判斷兩個類是否在同一個程序集實體中(內(nèi)存中的同一個實體)。若一個dll加載了兩遍,獲得兩個程序集對象,雖然兩個程序集中的類完全相同,但是依然無法相互轉(zhuǎn)換。文章來源:http://www.zghlxwxcb.cn/news/detail-637177.html
所以程序集最好有一個公共的存放處,統(tǒng)一的加載邏輯,不要養(yǎng)成需要某個類時直接去加載一遍dll的壞習慣。
也可以通過Assembly.GetExecutingAssembly()
直接獲取當前代碼所在的程序集,避免重復加載。文章來源地址http://www.zghlxwxcb.cn/news/detail-637177.html
到了這里,關(guān)于C# 子類強制轉(zhuǎn)換為父類異常,引出的C#Dll加載機制,以及同類名同命名空間同dll程序集在C#中是否為同一個類的研究。的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!