Type 類別提供三個描述名稱的屬性,看似相近卻大不同。本文透過實測代碼,釐清它們的定義、輸出差異與適用場景。
Type t = typeof(object);
Console.WriteLine(t.Name); // Object
Console.WriteLine(t.FullName); // System.Object
Console.WriteLine(t.AssemblyQualifiedName); // System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
非強名組件的 AssemblyQualifiedName 仍包含組件資訊(PublicKeyToken=null)。
Type t = typeof(Expression<Func<int, int>>);
Console.WriteLine(t.Name);
// Expression`1
Console.WriteLine(t.FullName);
// System.Linq.Expressions.Expression`1[[System.Func`2[[System.Int32, mscorlib],[System.Int32, mscorlib]], mscorlib]]
Console.WriteLine(t.AssemblyQualifiedName);
// System.Linq.Expressions.Expression`1[[System.Func`2[[System.Int32, mscorlib, ...],[System.Int32, mscorlib, ...]], mscorlib, ...]], System.Core, ...
關鍵發現:FullName 中巢狀泛型參數(如 Func<int,int>、int)會展開為組件限定名而非簡單 FullName。原因:Func<T> 位於 System.Core,int 位於 mscorlib,若僅用 FullName 無法在跨組件場景唯一識別類型。
List<int> 同理,類型參數在 FullName 中以 AssemblyQualifiedName 形式出現。
typeof(object).ToString(); // System.Object
typeof(Expression<Func<int,int>>).ToString();
// System.Linq.Expressions.Expression`1[System.Func`2[System.Int32,System.Int32]]
typeof(List<int>).ToString(); // System.Collections.Generic.List`1[System.Int32]
ToString() 返回不完全的 FullName:泛型參數顯示簡單名稱(無組件資訊),格式較易讀但不具唯一識別能力。
FullName 足夠(含命名空間)。AssemblyQualifiedName 確保全域唯一。ToString() 或 FullName 可讀性較佳。理解三者差異,關鍵在於「唯一性範圍」:Name < FullName < AssemblyQualifiedName。泛型類型參數在 FullName 中自動升級為組件限定名,是 .NET 為了跨組件類型身分識別做出的精妙設計。選對屬性,能避免序列化、配置、動態載入等場景的難以診斷錯誤。