Подтвердить что ты не робот

Метод может быть вызван только для типа, для которого Type.IsGenericParameter является истинным

Я получаю эту ошибку в подпрограмме, которая использует отражение, чтобы сбросить некоторые свойства объекта, что-то вроде кода ниже.

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.

Я пробовал проверять isGenericParameter как на obj, так и на p.PropertyType, но это кажется ложным для большинства свойств, в том числе тех, где p.GetValue работает.

Так что же такое "Тип, для которого Type.IsGenericParameter является истинным" и что более важно как избежать этой ошибки без try/catch?

4b9b3361

Ответ 1

Во-первых, вы сделали неверное предположение, то есть предположили, что members возвратил члены экземпляра System.Data.SqlClient.SqlConnection, которого у него нет. То, что было возвращено, это члены экземпляра System.Type.

Из документации MSDN для DeclaringType:

Получение свойства DeclaringMethodна типе IsGenericParameterсвойство ложно бросает InvalidOperationException.

Итак... понятно, что создается InvalidOperationException, так как, естественно, вы не имеете здесь никакого открытого типа. См. ответ Марка Гравеллса для объяснения открытых родовых типов.

Ответ 2

Так что же такое "Тип, для которого 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 от?

Ответ 3

Все подсказки там. Тип obj - это сам класс Type (или, скорее, странная производная RuntimeType).

В момент сбоя вы получаете свойство Type класса DeclaringMethod. Однако тип, описываемый этим экземпляром класса Type, это System.Data.SqlClient.SqlConnection, который не является общим типом метода.

Следовательно, попытка вызвать get на DeclaringMethod приводит к исключению.

Ключ: вы изучаете тип класса Type. Его немного круговое, но подумайте об этом: -

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

Что такое класс, описывающий?

Ответ 4

Как избежать этой ошибки без try/catch?

Ты почти наверняка не можешь. Когда вы вызываете p.GetValue, вы вызываете getter на это свойство, которое может вызывать любое исключение. Например, SqlConnection.ServerVersion выдает исключение, если соединение закрыто, и вы должны это обработать.

Откуда берутся эти дополнительные члены?

Ваш obj уже содержит объект RuntimeType, представляющий SqlConnection, а не экземпляр SqlConnection. obj.GetMembers() вернет 65 членов класса SqlConnection, но снова вызов GetType(), вы получите 188 членов RuntimeType.

Что такое IsGenericParameter?

Вместо представления класса вы можете иметь экземпляр RuntimeType, который представляет общий параметр для класса или метода (T и TOutput в List<T>.ConvertAll<TOutput>. В этом случае DeclaringMethod on объект, представляющий TOutput, позволит вам получить объект MethodInfo, представляющий метод ConvertAll<>. Однако, когда RuntimeType представляет класс, идея метода объявления не имеет смысла. Именно поэтому чтение свойства вызывает исключение, которое вы видели.