Ответ 1
Я намеренно проверяю только
null
, потому что я не хочу ограничивать значение ValueType равным егоdefault(T)
Это хорошее понимание, но не волнуйтесь, вы уже покрыты там. Нецелесообразно сравнивать T с default(T)
с использованием ==
в первую очередь; разрешение перегрузки не найдет уникального лучшего оператора ==
.
Конечно, вы можете сделать сравнение с .Equals
, но тогда вы рискуете сбой, если приемник имеет нулевое значение, чего именно вы пытаетесь избежать.
Есть ли более стандартный способ справиться с этой ситуацией?
Нет. По сравнению с нулем, это правильная вещь.
Как указано в спецификации С# в разделе 7.10.6: "Конструкция x == null
разрешена, даже если T может представлять тип значения, а результат просто определяется как false, когда T является типом значения."
Есть ли вероятность выхода из этого вопроса?
Конечно. Просто потому, что компиляция кода не означает, что у вас есть семантика, которую вы намереваетесь. Напишите несколько тестов.
Что действительно происходит под капотом, когда я делаю вызов и передаю тип значения?
Вопрос неоднозначен. Позвольте мне перефразировать это на два вопроса:
Что действительно происходит под капотом, когда я вызываю общий метод с аргументом типа, который является типом значения, не равным нулю?
Джиттер компилирует метод при первом вызове с этой конструкцией. Когда джиттер обнаруживает нулевую проверку, он заменяет его "false", потому что он знает, что тип значений, не имеющих значения NULL, когда-либо будет равен нулю.
Что действительно происходит под капотом, когда я вызываю общий метод с аргументом типа, который является ссылочным типом, но аргументом, который является типом структуры? Например:
interface IFoo : ISomeInterface<IFoo> {}
struct SFoo : IFoo { whatever }
...
DoFooInternal<IFoo>(new SFoo());
В этом случае джиттер не может преодолеть нулевую проверку, и сайт вызова не сможет избежать бокса. Экземпляр SFoo будет помещен в бокс, и ссылка на коробку SFoo будет проверена, чтобы увидеть, является ли она нулевым.