Странный вызов универсального метода с явным поведением универсального типа
У меня есть неуниверсальный класс с универсальным методом. Универсальный тип в этом методе определяет тип вывода и не может быть выведен из использования, поэтому я должен явно указать универсальный тип. Иногда этот тип передается из параметра типа метода универсального вызывающего, но в одном случае я должен явно предоставить его сам.
Проблема в том, что когда я вызываю мой явно предоставленный вызов метода универсального типа, кажется, что он не выполняется и возвращает совершенно не относящийся к делу тип. Я не могу отладить этот вызов и получить неверные результаты. Но это не нарушает исполнение, что особенно странно. Когда тот же метод вызывается из другого места, где универсальный тип передается из универсального типа метода вызывающей стороны, кажется, что все работает в соответствии с определением.
Я полностью потерян, что происходит.
Мое определение метода в интерфейсе (и реализовано позже в классе):
TRecord Update<TRecord>(int recordId, int? categoryId, string categoryName, string title)
where TRecord : Record;
мой Record
Класс неабстрактный, и от него наследуется только один тип:
public class Record : ProtectedEntity
{
...
}
public class RelatedRecord<T> : Record
{
public IList<T> Related { get; private set; }
...
}
Я вызываю мой метод, делая это:
var record = myRepo.Update<Record>(...);
Когда исполнение попадает в эту строку, я нажимаю F11 для отладки, но выполнение просто переходит к следующему предложению. Когда я проверяю record
переменная это не тип Record
скорее System.String
, имеющий значение параметра categoryName
, Это означает, что что-то действительно выполняется, но это определенно не тело моего общего метода.
Странно то, что везде работает один и тот же вызов, как и ожидалось.
Чем это можно объяснить и что я делаю не так?
2 ответа
Из того, что вы говорите, включая комментарий:
Если я пытаюсь получить доступ к каким-либо членам во время выполнения, это, конечно, вызывает исключение о несуществующих членах.
это звучит как ошибка компилятора или ошибка JIT. Это означает, что для его диагностики нам нужно больше знаний о компиляторе, который вы используете (точная версия), и / или JIT, который вы используете. В случае ошибки компилятора может быть достаточно, если вы можете просто показать сгенерированный IL, если вы знакомы с этим.
Обратите внимание, что самый последний предварительный просмотр VS включает в себя совершенно новый JIT (RyuJIT) и включает его по умолчанию для всей системы, так что, если вы установили предварительный просмотр VS, это было бы моим предположением. Если это так, вы можете отключить его тривиально, чтобы проверить.
Обратите внимание, что другой вариант здесь что-то вроде using
псевдоним, что псевдонимы Record
быть System.String
или псевдонимы var
быть System.String
(плюс некоторые неявные операторы преобразования и т. д.). Это маловероятно, но я видел, как это произошло;
Изменить: вышесказанное исключено вашим комментарием:
выполнение typeof(Record).ullName правильно возвращает мое полное имя типа, включая пространства имен, как и должно быть.
Таким образом, мы остаемся с ошибкой компилятора или JIT.
Если это ошибка RyuJIT, вот варианты ее отключения (я рекомендую сначала использовать конфигурацию, так как это легче всего сделать):
В качестве переменной среды: установите COMPLUS_useLegacyJit=1
В реестре: установите HKLM или HKCU, Software\Microsoft.NETFramework. Имя ключа: useLegacyJit. Тип: REG_DWORD. Значение: 1
В файле app.exe.config:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <runtime> <useLegacyJit enabled="1" /> </runtime> </configuration>
(это из отдельного обсуждения с MS, которое я проводил ранее)
Если вы не получаете исключение типа времени выполнения, я могу заподозрить ошибку в отладчике Visual Studio, с которой я столкнулся. Если у вас есть две локальные переменные с одинаковыми именами в одном и том же методе, отладчик может их перепутать:
private void DoSomething(int x)
{
{
var s = "STRING!";
Console.WriteLine(s);
}
{
var s = 5;
Console.WriteLine(s);
}
}
Я не знаю, действительно ли приведенный выше пример воспроизведет проблему, но я видел поведение отладчика, когда вы наводите курсор мыши на секунды, и он показывает его как "STRING!", А не 5. Это было бы первым делом. Я бы проверил, что у вас нет другой локальной переменной в том же методе с именем "запись".