Мені вдалося знайти статтю Microsoft Connect, яка детально обговорює цю проблему:
На жаль, така поведінка є конструктивною, і не існує простого рішення, щоб дозволити використовувати параметри типу, які можуть містити типи значень.
Якщо типи, як відомо, є еталонними типами, перевантаження за замовчуванням визначених на об’єктних тестах змінних для рівності опор, хоча тип може визначати власну власну перевантаження. Компілятор визначає, яку перевантаження використовувати на основі статичного типу змінної (визначення не є поліморфним). Отже, якщо ви зміните свій приклад, щоб обмежити параметр загального типу T нетипованим типовим типом (наприклад, виняток), компілятор може визначити конкретну перевантаження, яку слід використовувати, і буде скомпільований наступний код:
public class Test<T> where T : Exception
Якщо типи, як відомо, є типовими типами, виконує специфічні тести рівності значень на основі точних використаних типів. Тут немає хорошого "за замовчуванням" порівняння, оскільки порівняння посилань не має значення для типів значень і компілятор не може знати, яке саме порівняння значення виділяти. Компілятор може викликати виклик до ValueType.Equals (Object), але цей метод використовує відображення і є досить неефективним порівняно з конкретними порівняннями значень. Тому, навіть якщо ви мали б вказати обмеження типу значення на T, компілятор не може створити тут:
public class Test<T> where T : struct
У представленому вами випадку, коли компілятор навіть не знає, чи є T значенням або еталонним типом, аналогічно нічого не можна створити, що було б дійсним для всіх можливих типів. Порівняльне посилання не було б дійсним для типів значень, і якесь порівняння значення було б несподіваним для типів посилань, які не перевантажують.
Ось що ви можете зробити ...
Я підтвердив, що обидва ці методи працюють для загального порівняння еталонних і значущих типів:
object.Equals(param, default(T))
або
EqualityComparer<T>.Default.Equals(param, default(T))
Для порівняння з оператором "==" вам потрібно буде скористатися одним із таких методів:
Якщо всі випадки T походять з відомого базового класу, ви можете повідомити про це компілятору, використовуючи загальні обмеження типу.
public void MyMethod<T>(T myArgument) where T : MyBase
Потім компілятор розпізнає, як виконувати операції над MyBase
і не кидає "Оператор" == "не може бути застосований до операндів помилки типу" T "і" T ", які ви зараз бачите.
Іншим варіантом було б обмежити T будь-яким типом, який реалізується IComparable
.
public void MyMethod<T>(T myArgument) where T : IComparable
А потім скористайтеся CompareTo
методом, визначеним інтерфейсом IComparable .
if (myArgument?.Equals( default(T) ) != null )
.