Я не могу понять приведенные ниже пункты о параметрах неограниченного типа.
Введите параметры, не имеющие ограничений, например T в общедоступном классе. SampleClass{} называются параметрами неограниченного типа.
Для параметров неограниченного типа действуют следующие правила: Вы можете сравнивать нулевой. Если неограниченный параметр сравнивается с нулем, сравнение всегда будет возвращать false, если аргумент типа является типом значения.
Я не нашел ни одного примера вышеперечисленных пунктов. Будет здорово, если кто-нибудь даст мне пример, чтобы понять суть.
Попробуйте сами bool Test<T>(T val) => val == null;.
К вашему сведению, техническая причина в том, что вы звоните оператору (object) == (object). Любой тип значения будет помещен в рамку, что всегда приведет к ненулевой ссылке.
@JeremyLakeman, если T=Int и Val=0, то верните False ---___---- если T=String и Val = "" тогда тоже верните false ............ Microsoft: сравнение всегда будет возвращать false, если аргумент типа является типом значения. sring не является типом значения
Сгенерированный IL — это ldarg.0, box !!T, ldnull, ceq, операция box ничего не сделает с существующей ссылкой; Sharplab.io/…null не совсем то же самое, что default(T). Несвязанные типы не имеют оператора ==, поэтому для сравнения с EqualityComparer<T>.Default.Equals() необходимо использовать default(T). Вызывающая сторона может указать аргумент типа и указать, является ли аргумент типа значением. например Test<int>(0);
@Servy this, если аргумент типа является типом значения. «Почему ставится это условие, если оно показывает то же поведение, что и ссылочный тип?
@JeremyLakeman Спасибо, это был ответ на мой вопрос<3
@YaSecu Как вы думаете, почему сравнение ссылочного типа с нулевым всегда неверно?
@Servy Ты открыл мне разум, я был в темноте, я понимаю, спасибо





Обе эти функции приводят к одному и тому же IL;
bool Test1<T>(T val) => val == null;
bool Test2<T>(T val) where T:class => val == null;
IL_0000: ldarg.0
IL_0001: box !!T
IL_0006: ldnull
IL_0007: ceq
IL_0009: ret
Если вызывающая сторона передает параметр типа значения;
Test1<int>(0) == false;
Тогда целочисленный аргумент будет помещен в объект, что всегда приведет к ненулевой ссылке. Поэтому сравнение с null всегда будет ложным.
Однако, если вызывающая сторона передает параметр Nullable<T>. Несмотря на то, что это тип значения, бокс значение приведет к null.
Test1<int?>(null) == true;
Подобная упаковка значения — это деталь реализации, которая может измениться в будущих версиях. Таким образом, ссылка на язык, которую вы цитируете, вместо этого говорит о побочном эффекте этой реализации, а не о причине.
Для полноты картины можно сказать еще кое-что об общих функциях и равенстве.
Передача явного аргумента Nullable<T> также допустима и приводит к тому же IL.
bool Test3<T>(T? val) where T:struct => val == null;
bool Test4<T>(T? val) where T:struct => !val.HasValue;
IL_0000: ldarga.s val
IL_0002: call instance bool valuetype [System.Runtime]System.Nullable`1<!!T>::get_HasValue()
IL_0007: ldc.i4.0
IL_0008: ceq
IL_000a: ret
Но для типов значений нет оператора == по умолчанию;
bool Test5<T>(T val) where T:struct => val == null;
bool Test6<T>(T val) where T:struct => val == default(T);
error CS0019: Operator '==' cannot be applied to operands of type 'T' and '<null>'
error CS0019: Operator '==' cannot be applied to operands of type 'T' and 'T'
Вместо этого вы можете использовать компаратор по умолчанию;
public bool Test7<T>(T val) => EqualityComparer<T>.Default.Equals(val, default(T));
Начиная с .net 7, вы можете добавить ограничение, которое реализуется числовыми типами .net;
public bool Test8<T>(T val) where T : IEqualityOperators<T,T,bool> => val == default(T);
Что из этого ты не понимаешь?