2010-09-21 30 views
17

我在我的(巨大的).NET 4項目中遇到了一個奇怪的行爲。在代碼中的某些時候,我指的是一個完全合格的類型,說:如果typeof(Xyz)存在,爲什麼System.Type.GetType(「Xyz」)返回null?

System.Type type = typeof (Foo.Bar.Xyz); 

後來,我這樣做:

System.Type type = System.Type.GetType ("Foo.Bar.Xyz"); 

和我回去null。我無法理解爲什麼會發生這種情況,因爲我的類型名稱是正確的,並且我已經檢查了其他類型,並且他們得到了正確解決。此外,下面的LINQ查詢查找類型:

var types = from assembly in System.AppDomain.CurrentDomain.GetAssemblies() 
      from assemblyType in assembly.GetTypes() 
      where assemblyType.FullName == typeName 
      select assemblyType; 

System.Type type = types.FirstOrDefault(); 

在什麼情況System.Type.GetType可能會失敗原因的任何?

我終於不得不求助於這段代碼,而不是GetType

System.Type MyGetType(string typeName) 
{ 
    System.Type type = System.Type.GetType (typeName); 

    if (type == null) 
    { 
     var types = from assembly in System.AppDomain.CurrentDomain.GetAssemblies() 
        from assemblyType in assembly.GetTypes() 
        where assemblyType.FullName == typeName 
        select assemblyType; 

     type = types.FirstOrDefault(); 
    } 

    return type; 
} 

回答

26

如果你只是給出一個類名(確實需要在命名空間方面完全合格),Type.GetType(string)只會在當前正在執行的程序集和mscorlib中查找。如果您想從任何其他程序集中獲取類型,則需要指定絕對全名,包括程序集信息。正如弗朗索瓦所說,Type.AssemblyQualifiedName是一個很好的看待這個問題的方法。這裏有一個例子:

using System; 
using System.Windows.Forms; 

class Test 
{ 
    static void Main() 
    { 
     string name = typeof(Form).AssemblyQualifiedName; 
     Console.WriteLine(name); 

     Type type = Type.GetType(name); 
     Console.WriteLine(type); 
    } 
} 

輸出:

System.Windows.Forms.Form中,System.Windows.Forms的,版本= 4.0.0.0,文化=中立,
公鑰= b77a5c561934e089
System.Windows.Forms.Form中

需要注意的是,如果你(在這種情況下,像Form)使用強命名程序集,你必須包括所有組件信息 - 版本,公鑰令牌等

如果您使用非強命名程序集,它更容易 - 是這樣的:

Foo.Bar.Baz, MyCompany.MyAssembly 

一個名爲Baz型命名空間Foo.Bar,裝配MyCompany.MyAssembly。注意最後沒有「.dll」 - 這是文件名的一部分,但不是程序集名稱。

您還應該瞭解C#名稱和CLR名稱之間的區別,例如嵌套類和泛型。例如,typeof(List<>.Enumerator)的名稱爲System.Collections.Generic.List`1+Enumerator[T]。泛型方面很棘手,但嵌套類型很簡單 - 它只是用「+」而不是「。」來表示。你會在C#中使用。

+0

非常感謝您的回覆。事實上,我到目前爲止解決的所有其他類型都位於相同的程序集或mscorlib中,所以我之前沒有發現該錯誤。 – 2010-09-21 09:24:11

+0

即使程序集具有強名稱,也可以使用部分程序集信息提供'System.Type.GetType'。我已經檢查過'System.Type.GetType(「Foo.Bar.Baz,MyCompany.MyAssembly」),即使「MyCompany.Assembly」具有強名稱,它也能正常工作。 – 2010-09-21 09:26:00

+0

以供將來參考,如果您想在代碼高亮中使用反引號(並且您可能會;),請使用雙反引號來開始和關閉引用:)。參見[這裏](http://meta.stackexchange.com/q/82718/237379)。 – Noctis 2014-07-27 02:30:37

4

據我知道的GetType名爲Foo.Bar.dll,我組裝查找「XYZ」假設它不存在。

GetType依賴於在程序集中傳遞Xyz的確切路徑。組裝和命名空間不必相關。

嘗試System.Type type = System.Type.GetType(typeof(Foo.Bar.Xyz).AssemblyQualifiedName)看看是否有效。

您找到LINQ示例的原因是您正在使用GetAssemblies,它獲取已加載到當前執行上下文中的程序集,因此具有查找程序集內所有類型所需的詳細信息。

4

MSDN documentation(我的重點):

如果typeName的包括命名空間,但不集名稱,這種方法搜索只有調用對象的組裝的Mscorlib.dll,按照這個順序。如果typeName用部分或完整程序集名稱完全限定,則此方法在指定程序集中搜索。如果裝配體名稱很強,則需要一個完整的裝配體名稱。

1

我只是偶然發現了一個類似的問題,要離開這個位置

的首先你可以將字符串

var type = System.Type.GetType("Foo.Bar.Xyz, Assembly.Name"); 

然而,對於組件這隻能如果沒有一個強有力的指定的AssemblyName名稱。解釋已經在西蒙斯回答If the assembly has a strong name, a complete assembly name is required.

我的問題是我不得不在運行時從字符串解決System.Dictionary<?,?>。對於Dictionary<int, string>這可能很容易,但Dictionary<int, Image>呢?

這將導致

var typeName = "System.Collections.Generic.Dictionary`2[System.Int32, [System.Drawing.Image, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a]]"; 

但我不想寫的強名稱。特別是因爲我不打算包含這些版本,因爲我打算用我的代碼來定位多個框架。

因此,這裏是我的解決方案

privat statice void Main() 
    { 
     var typeName = "System.Collections.Generic.Dictionary`2[System.Int32, [System.Drawing.Image, System.Drawing]]"; 
     var type = Type.GetType(typeName, ResolveAssembly, ResolveType); 
    } 

    private static Assembly ResolveAssembly(AssemblyName assemblyName) 
    { 
     if (assemblyName.Name.Equals(assemblyName.FullName)) 
      return Assembly.LoadWithPartialName(assemblyName.Name); 
     return Assembly.Load(assemblyName); 
    } 

    private static Type ResolveType(Assembly assembly, string typeName, bool ignoreCase) 
    { 
     return assembly != null 
      ? assembly.GetType(typeName, false, ignoreCase) 
      : Type.GetType(typeName, false, ignoreCase); 
    } 

Type.GetType(...)具有acceps組裝一個FUNC過載,並鍵入解決這整齊。不推薦使用Assembly.LoadWithPartialName,但如果在將來刪除它,我可以考慮替換(迭代當前AppDomain中的所有程序集並比較部分名稱)。

相關問題