有時我期望只是創建出物件,但是不要呼叫物件的構造方法,可以通過使用 FormatterServices 的 GetUninitializedObject 函式來實作只創建物件不呼叫建構式方法
這個 FormatterServices.GetUninitializedObject 方法大部分是用在做序列化使用的,然而在很多 IOC 容器,也都使用此方法來創建物件,而通過其他方法拿到建構式
在 WPF 的 XAML 創建物件,也有用到此方法,詳細請看 dotnet 讀 WPF 源代碼筆記 XAML 創建物件的方法
以下是一個實作的例子
Foo foo = null;
try
{
foo = (Foo) FormatterServices.GetUninitializedObject(typeof(Foo));
var constructorInfo = typeof(Foo).GetConstructor(new Type[0]);
constructorInfo!.Invoke(foo, null);
}
catch
{
}
class Foo
{
}
此方法可以用來處理在建構式時,如果拋出了例外,但是此物件的 Dispose 需要被顯式呼叫的問題,因為如果在建構式拋出例外,那么在 C# 代碼層面將拿不到此物件,也就無法呼叫對應的 Dispose 釋放
如以下代碼,可以看到 Foo 物件依然是空
private void F1()
{
Foo foo = null;
try
{
foo = new Foo();
}
catch
{
// 忽略
}
}
class Foo : IDisposable
{
public Foo()
{
throw new Exception("lindexi is doubi");
}
~Foo()
{
}
public void Dispose()
{
GC.SuppressFinalize(this);
}
}
此時如果期望呼叫 Foo 物件的 Dispose 方法,將會因為拿不到物件而無法呼叫
解決此方法的做法就是通過只創建物件而不呼叫構造的方法,先拿到物件然后再呼叫構造,如果構造出錯,依然還可以呼叫物件的 Dispose 方法
private void F2()
{
Foo foo = null;
try
{
foo = (Foo) FormatterServices.GetUninitializedObject(typeof(Foo));
var constructorInfo = typeof(Foo).GetConstructor(new Type[0]);
constructorInfo!.Invoke(foo, null);
}
catch
{
// 忽略
}
finally
{
try
{
foo?.Dispose();
}
catch
{
// 可以呼叫到 Dispose 方法
}
}
}
class Foo : IDisposable
{
public Foo()
{
throw new Exception("lindexi is doubi");
}
~Foo()
{
Dispose();
}
public void Dispose()
{
GC.SuppressFinalize(this);
throw new Exception($"lsj is doubi");
}
}
這個設計可以用來解決,如果物件的建構式還沒完全完成,呼叫釋放函式將會拋出例外,如果沒有使用如上方法,那么在釋放函式的例外將會在 GC 回收執行緒拋出,而讓應用程式退出
這就是為什么有很多容器和底層庫喜歡使用此方法創建物件的原因
本文代碼還請到 github 或 gitee 上閱讀代碼
可以通過如下方式獲取本文的源代碼,先創建一個空檔案夾,接著使用命令列 cd 命令進入此空檔案夾,在命令列里面輸入以下代碼,即可獲取到本文的代碼
git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 11077dd21a4ee5314757536ca379ecca6956b040
以上使用的是 gitee 的源,如果 gitee 不能訪問,請替換為 github 的源
git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
獲取代碼之后,進入 HojeneceabuHallwhallhebo 檔案夾
FormatterServices.GetUninitializedObject(Type) Method (System.Runtime.Serialization)
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/288016.html
標籤:.NET技术
