Метод может быть вызван только для типа, для которого Type.IsGenericParameter имеет значение true - PullRequest
19 голосов
/ 28 августа 2009

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

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 имеет значение true».

На этом этапе в отладчике объект отображается как

  {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 имеет значение true» и, что более важно, как избежать этой ошибки без попытки / улова?

Ответы [ 5 ]

15 голосов
/ 28 августа 2009

Так что же такое «тип, для которого Type.IsGenericParameter имеет значение true»

Это означает, что это аргумент универсального типа в открытом универсальном типе - то есть, где мы еще не выбрали T; например:

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

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

Итак, у вас есть открытые дженерики? Возможно, если вы можете привести пример, откуда вы взяли свой obj?

13 голосов
/ 28 августа 2009

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

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

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

Итак ... понятно, что выбрасывается InvalidOperationException, поскольку, естественно, вы не имеете здесь дело с открытым универсальным типом. См. Marc Gravells answer для объяснения открытых универсальных типов.

3 голосов
/ 28 августа 2009

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

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

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

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

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

Что описывает класс?

1 голос
/ 26 декабря 2018

Моя проблема была решена путем удаления повторяющихся полей и таблиц в моей модели и прокомментировал определение запроса и удаленного хранилища: в XML-файле Model.edmx.

1 голос
/ 28 августа 2009

Как избежать этой ошибки без попытки / улова?

Вы почти наверняка не можете. Когда вы вызываете p.GetValue, вы вызываете метод получения этого свойства, что может вызвать любое исключение. Например, 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 представляет класс, идея объявления метода не имеет смысла. Вот почему чтение свойства вызывает исключение, которое вы видели.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...