Правила параметров неограниченного типа в Generics (C#)

Я не могу понять приведенные ниже пункты о параметрах неограниченного типа.

Введите параметры, не имеющие ограничений, например T в общедоступном классе. SampleClass{} называются параметрами неограниченного типа.

Для параметров неограниченного типа действуют следующие правила: Вы можете сравнивать нулевой. Если неограниченный параметр сравнивается с нулем, сравнение всегда будет возвращать false, если аргумент типа является типом значения.

Я не нашел ни одного примера вышеперечисленных пунктов. Будет здорово, если кто-нибудь даст мне пример, чтобы понять суть.

Что из этого ты не понимаешь?

Servy 26.02.2024 03:18

Попробуйте сами bool Test<T>(T val) => val == null;.

Jeremy Lakeman 26.02.2024 03:21

К вашему сведению, техническая причина в том, что вы звоните оператору (object) == (object). Любой тип значения будет помещен в рамку, что всегда приведет к ненулевой ссылке.

Jeremy Lakeman 26.02.2024 03:35

@JeremyLakeman, если T=Int и Val=0, то верните False ---___---- если T=String и Val = "" тогда тоже верните false ............ Microsoft: сравнение всегда будет возвращать false, если аргумент типа является типом значения. sring не является типом значения

YaSecu 26.02.2024 03:36

Сгенерированный IL — это ldarg.0, box !!T, ldnull, ceq, операция box ничего не сделает с существующей ссылкой; Sharplab.io/…null не совсем то же самое, что default(T). Несвязанные типы не имеют оператора ==, поэтому для сравнения с EqualityComparer<T>.Default.Equals() необходимо использовать default(T). Вызывающая сторона может указать аргумент типа и указать, является ли аргумент типа значением. например Test<int>(0);

Jeremy Lakeman 26.02.2024 03:40

@Servy this, если аргумент типа является типом значения. «Почему ставится это условие, если оно показывает то же поведение, что и ссылочный тип?

YaSecu 26.02.2024 03:45

@JeremyLakeman Спасибо, это был ответ на мой вопрос<3

YaSecu 26.02.2024 03:47

@YaSecu Как вы думаете, почему сравнение ссылочного типа с нулевым всегда неверно?

Servy 26.02.2024 04:13

@Servy Ты открыл мне разум, я был в темноте, я понимаю, спасибо

YaSecu 26.02.2024 04:22
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
9
69
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Обе эти функции приводят к одному и тому же 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);

Другие вопросы по теме