在 dotnet 裏面,可使用 FormatterServices 的 GetUninitializedObject 方法能夠實現只建立對象,而不調用對象的構造函數方法。而若是在使用此方法時,存在了 DLL 缺失的狀況,此時可否讓此方法運行經過,建立出空的對象html
答案是能夠建立成功,也能夠建立不成功。當全部碰到的字段都是引用類型的時候,能夠建立成功。若是存在值類型,可是值類型的 DLL 定義文件被刪除,將會失敗git
下面來寫一點測試的邏輯,以下面代碼分別定義 F1 和 F2 和 F3 三個不一樣的類型github
class F1 { public F2 F2 { get; } = new F2(); } class F2 { public F3 F3 { get; } = new F3(); } public class F3 { }
在 Main 函數裏面使用下面代碼調用 FormatterServices 的 GetUninitializedObject 方法建立對象函數
class Program { static void Main(string[] args) { var f1 = FormatterServices.GetUninitializedObject(typeof(F1)); } }
接着將 F3 類放在另外一個項目裏面,而後讓此項目引用包含 F3 類的項目。在構建完成以後,刪除包含 F3 類的項目的輸出 DLL 文件。接着運行 Main 方法,能夠看到實際上 f1 對象仍是被建立纔出來,不會炸掉post
能夠經過以下方式獲取本文的源代碼,先建立一個空文件夾,接着使用命令行 cd 命令進入此空文件夾,在命令行裏面輸入如下代碼,便可獲取到本文的代碼命令行
git init git remote add origin https://gitee.com/lindexi/lindexi_gd.git git pull origin 2f00793486fcb1962de7e368ec527cf1169db135
以上使用的是 gitee 的源,若是 gitee 不能訪問,請替換爲 github 的源code
git remote remove origin git remote add origin https://github.com/lindexi/lindexi_gd.git
獲取代碼以後,進入 JinaldalurhaBelnallbune 文件夾orm
其實此時即便獲取 F2 的類型,經過反射拿到全部的成員,也是能夠獲取到的,以下圖htm
能夠看到本來是 F3 的類型對應的屬性,在反射拿到的是 System.Reflection.RuntimePropertyInfo
類型
能夠看到對應的模塊被刪除時,只會提示說文件找不到,而不會讓反射失敗
接下來試試使用結構體的方式,也就是字段實際是值類型的方式,修改 F2 和 F3 從引用類型修改成結構體,代碼以下
struct F2 { public F3 F3 { get; } } public struct F3 { static F3() { } }
依然將 F3 放在另外一個程序集,而後在輸出文件裏面刪除此程序集的 DLL 文件。嘗試運行代碼,能夠看到此時運行將會失敗
緣由是由於值類型須要計算對象的佔用的內存空間的大小,在準備建立 F1 的時候須要開始計算 F2 的佔用空間,由於 F2 是一個結構體。可是 F2 裏面引用了 F3 類型,此時 F2 就須要開始計算 F3 的空間,然而定義 F3 佔用空間大小的數據放在了被刪除的程序集裏面,所以拿不到 F3 的佔用空間大小,從而計算不出 F2 的空間大小,也就沒法建立 F1 對象,所以失敗
那爲何 F3 的佔用空間大小須要放在定義 F3 的程序集裏面,不能放在被引用的如 F2 所在的程序集裏面?緣由在於 dotnet 的應用能夠支持 DLL 兼容更新,如我能夠方便的更改 F3 類型的定義,如添加一個字段。那麼此時 F3 的佔用內存空間大小天然就須要修改了。然而此時我能夠作到不更改 F2 所在的程序集,只須要更新 F3 所在的程序集便可,這就是由於在運行時裏面讀取了 F3 所在的程序集拿到了 F3 的佔用內存空間的大小,不須要依賴在 F2 所在的程序集的定義
能夠經過以下方式獲取本文的源代碼,先建立一個空文件夾,接着使用命令行 cd 命令進入此空文件夾,在命令行裏面輸入如下代碼,便可獲取到本文的代碼
git init git remote add origin https://gitee.com/lindexi/lindexi_gd.git git pull origin 415664a5516c778db662dd519e9114a320a4d690
以上使用的是 gitee 的源,若是 gitee 不能訪問,請替換爲 github 的源
git remote remove origin git remote add origin https://github.com/lindexi/lindexi_gd.git
獲取代碼以後,進入 JinaldalurhaBelnallbune 文件夾
若是不是直接的引用的類型找不到定義的程序集,那依然能夠成功,將 F2 從結構體修改成引用類型,以下面代碼
class F2 { public F3 F3 { get; } }
此時刪除 F3 所在的程序集,依然能夠建立出來 F1 對象
經過上文能夠了解到 F1 對象的內存空間,能夠計算出來,由於 F2 是引用類型,引用類型佔用的字段內存空間是固定的。因此就不須要再去計算 F2 裏面包含的 F3 結構體的佔用空間
固然,依然讓 F2 是結構體類型,可是將 F3 修改成引用類型,也能建立成功。緣由是 F2 結構體在不知道 F3 的程序集時依然能夠根據引用類型佔用的字段空間是固定的,計算出包含 F3 的屬性的字段佔用的內存,所以不須要去讀取 F3 所在的程序集
經過上文能夠了解到 dotnet 裏面加載程序集的機制