2009-08-28 27 views
17

我在使用反射轉儲某些對象屬性(如下面的代碼)的例程上收到此錯誤。只能在Type.IsGenericParameter爲true的Type上調用方法

MemberInfo[] members = obj.GetType().GetMembers(BindingFlags.Public | BindingFlags.Instance) ; 

foreach (MemberInfo m in members) 
{ 
    PropertyInfo p = m as PropertyInfo; 
    if (p != null) 
    { 
     object po = p.GetValue(obj, null); 

     ... 
    } 
} 

實際的錯誤是「異常已被拋出通過調用目標」 與內部異常「方法可以僅在一個類型爲哪些Type.IsGenericParameter爲真稱爲」。

在此階段在調試器的obj顯示爲

{Name = "SqlConnection" FullName = "System.Data.SqlClient.SqlConnection"} 

與類型System.RuntimeType

的方法,m爲{System.Reflection.MethodBase DeclaringMethod}

注意obj是類型System.RuntimeType和成員包含188項,而簡單的 typeof(System.Data.SqlClient.SqlConnection).GetMembers(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance)僅返回65.

我試着在obj和p.PropertyType上檢查isGenericParameter,但對於大多數屬性(包括p.GetValue工作的那些屬性),這似乎都是錯誤的。

那麼到底什麼是「Type.IsGenericParameter爲true的類型」,更重要的是 如果沒有try/catch,我該如何避免這個錯誤?

回答

13

首先,你已經取得了不正確的假設,也就是說,你假定members已返回System.Data.SqlClient.SqlConnection的實例的成員,但它沒有。返回的是System.Type實例的成員。

從MSDN文檔DeclaringType

獲取上類型,其IsGenericParameter 屬性設置爲false拋出 InvalidOperationExceptionDeclaringMethod財產 。

所以......這是可以理解的InvalidOperationException被拋出,因爲自然,你沒有在這裏處理一個開放的泛型類型。請參閱Marc Gravells answer以獲取關於開放泛型類型的解釋。

+2

我想我已經開始看到光。這並不是說p.GetValue可以「只對Type.IsGenericParameter爲true的Type進行調用」,而是隻能調用由p表示的基礎屬性,在本例中爲DeclaringMethod,即Type.IsGenericParameter爲真正。 – sgmoore 2009-08-28 12:00:29

+1

準確地說 - 這就是「調用目標拋出異常」的意思,在這種情況下,「調用的目標」是'DeclaringMethod'屬性獲取器,並且您將通過閱讀獲得相同的「IsGenericParameter」異常直接使用「obj.DeclaringMethod」。 – stevemegson 2009-08-28 13:02:18

+0

我已經將這個答案標記爲我接受的答案,因爲它是最有幫助的,但實際上大多數其他答案也有幫助。謝謝大家。 – sgmoore 2009-08-28 13:26:40

13

那麼究竟什麼是「鍵入該Type.IsGenericParameter是真正的」

這意味着它是在一個開放的泛型類型,泛型類型參數 - 即在這裏我們就不挑了T然而;例如:

// true 
bool isGenParam = typeof(List<>).GetGenericArguments()[0].IsGenericParameter; 

// false (T is System.Int32) 
bool isGenParam = typeof(List<int>).GetGenericArguments()[0].IsGenericParameter; 

所以;你有沒有開放式的泛型?也許如果你能舉一個你從哪裏得到obj的例子嗎?

+0

OP確實在obj中聲明瞭它的System.RuntimeType類型 – AnthonyWJones 2009-08-28 11:15:41

+0

從我所看到的問題來看,問題不在於開放泛型的存在,而在於正常類型的存在:) – 2009-08-28 11:34:26

+0

我以異常(在這裏是一個SqlException),它被傳遞給我的轉儲例程。轉儲例程是遞歸的,因此將在異常中的所有屬性和字段上調用轉儲。 我的代碼中有一些泛型,但沒有開放泛型。 令我困惑的是,這個錯誤似乎是說,如果GenericParameter爲true,p.GetValue才起作用,這顯然不是真的。 – sgmoore 2009-08-28 11:47:57

3

所有的線索都在那裏。 obj的類型是Type類本身(或者更奇怪的RuntimeType派生)。

在循環失敗時,您已到達名爲DeclaringMethodType類屬性。然而,Type類的這個實例描述的類型是System.Data.SqlClient.SqlConnection,它不是方法的通用類型。

因此,嘗試調用DeclaringMethod上的get會導致異常。

關鍵是您正在檢查類別Type的類型。它有點圓形,但想到這一點: -

SqlConnection s = new SqlConnection(); 
Type t = s.GetType() 
Type ouch = t.GetType() 

什麼是類ouch描述?

1

如何在沒有try/catch的情況下避免此錯誤?

你幾乎肯定不能。當你打電話給p.GetValue時,你正在調用該屬性的getter,這可能會引發任何異常。例如,如果連接關閉,SqlConnection.ServerVersion將引發異常,您必須處理該異常。

這些額外的成員來自哪裏?

obj已經包含較SqlConnectionRuntimeType對象,而不是SqlConnection一個實例。 obj.GetMembers()將返回SqlConnection類的65個成員,但通過再次呼叫GetType(),您將獲得RuntimeType的188個成員。

什麼是IsGenericParameter

而是代表一類,你可以有一個表示泛型參數類或方法(在List<T>.ConvertAll<TOutput>TTOutputRuntimeType一個實例。在這種情況下,DeclaringMethod表示TOutput的對象會讓你代表ConvertAll<>方法MethodInfo對象。然而,當RuntimeType代表一個階級,一個聲明方法的想法是沒有意義的。這就是爲什麼讀取屬性會導致你所看到的異常。

相關問題