.NET 2.0: вызов методов с использованием отражений и обобщений вызывает исключение - PullRequest
2 голосов
/ 15 июня 2010

Я новичок в Stack Overflow, так что прости меня.Я только что начал переходить на C # и застрял в проблеме.

Я хочу передать универсальный класс и вызвать метод из этого класса.Итак, мой код выглядит так:

public void UpdateRecords<T>(T sender) where T : new() //where T: new() came from Resharper
{
    Type foo = Type.GetType(sender.GetType().ToString());
    object[] userParameters = new object[2];
    userParameters[0] = x;
    userParameters[1] = y;
    sender = new T(); //This was to see if I could solve my exception problem
    MethodInfo populateRecord = foo.GetMethod("MethodInOtherClass");
    populateMethod.Invoke(sender, userParameters);
}

Исключение: «Ссылка на объект не установлена ​​для экземпляра объекта.»

Опять же, я действительно извиняюсь, так как я почти брендновичок в C #, и это первый раз, когда я обращаюсь к рефлексии и дженерикам.Спасибо!

Ответы [ 4 ]

6 голосов
/ 15 июня 2010

Прежде всего, я бы порекомендовал запустить этот код в отладчике и повернуть один «Break on Exception» , чтобы помочь определить, какая строка вызывает ошибку. Это полезный метод отладки, который поможет вам быстрее находить подобные проблемы в будущем. Перейдите к Debug >> Exceptions в VS и установите флажок для Common Language Runtime Exceptions в столбце Thrown.

Теперь к вашей проблеме. Вероятно, что sender передается как null. Если это так, строка:

Type foo = Type.GetType(sender.GetType().ToString()); 

бросит NullReferenceException. Вместо этого вы можете использовать:

Type foo = typeof(T); 

, который определяет тип общего параметра, не требуя его экземпляра.

Теперь, не зная больше о том, что пытается сделать ваш код, невозможно сказать, является ли создание экземпляра T правильным решением. То, что ReSharper рекомендует добавлять where T : new(), не означает, что это уместно - если вы не знаете , что это правильное поведение .

Наконец, я не знаю, есть ли веская причина для использования отражения для вызова MethodInOtherClass - возможно, есть. Но так как вы новичок в C #, я упомяну, что если тип T всегда будет подклассом некоторого базового типа A или всегда будет реализовывать некоторый интерфейс I, который включает метод, который вы хотите вызвать, Вы можете просто применить общее ограничение, чтобы компилятор знал это. Затем вы можете вызвать метод, не возвращаясь к использованию отражения:

public void UpdateRecords<T>(T sender) 
   where T : SomeBaseClass_Or_SomeInterface_ThatDefinesMethod
{
  sender = new T();
  sender.MethodInOtherClass( x, y );
}

Намного приятнее.

Один последний комментарий. Необычно передать аргумент методу, а затем полностью его игнорировать - только для создания экземпляра в методе. Есть случаи, когда это уместно - но я склонен рассматривать это как запах кода . Если возможно, я бы попытался либо избавиться от аргумента sender, либо изменить код, чтобы сначала проверить его на нулевое значение, а создать его только тогда.

2 голосов
/ 15 июня 2010

sender.GetType().ToString() возвращает имя типа без имени сборки.

Type.GetType ожидает имя типа с именем сборки (если тип не входит в исполняющую сборку или mscorlib). Если тип не может быть найден (например, из-за отсутствующего имени сборки), он возвращает нулевую ссылку.


Попробуйте изменить код на

Type foo = sender.GetType();

или даже просто

Type foo = typeof(T);
1 голос
/ 15 июня 2010

Вы просто должны быть в состоянии сделать это, чтобы получить тип:

Type foo = typeof(T);

Вы не указали, где вы получаете NullReferenceException, но мне интересно, возвращается ли foo как ноль...

0 голосов
/ 15 июня 2010

Или:

  1. sender равно нулю, поэтому sender.GetType() завершится ошибкой.
  2. foo.GetMethod("MethodInOtherClass") возвращает ноль, поэтому populateMethod.Invoke() не удастся.
  3. MethodInOtherClass зависит от определенных предварительных условий (ненулевых ссылок), поэтому он потерпит неудачу, если они отсутствуют.
...