Тип C# Тип строки? это TypeKind.Class
Перефразированный вопрос: у меня есть этот компаратор равенства с универсальным типом, ограниченным
class
public class ReferenceEqualityComparer<T> : IEqualityComparer<T> where T : class
{
public static ReferenceEqualityComparer<T> Default => new();
public bool Equals(T? x, T? y) => ReferenceEquals(x, y);
public int GetHashCode(T? obj) => RuntimeHelpers.GetHashCode(obj);
}
когда класс скажем
public class A
{
public string? P1{get; set;}
}
потребляется генератором кода
[Generator]
public class MyCodeGenerator : ISourceGenerator
{
}
NetAnalyzer говорит, что имеет TypeKind класса
но когда я это сделаю,
#nullable enable
[TestMethod]
public void RefTest()
{
string? s1 = "adsad";
string? s3 = s1;
Assert.IsTrue(ReferenceEqualityComparer<string?>.Default.Equals(s1, s3));
}
#nullable restore
он говорит, что не соответствует ограничению «класс». Несмотря на то, что анализатор сообщает мне, что это класс, я что-то здесь упускаю? или я неправильно понял концепцию?
Исходный вопрос: Согласно описанию Nullable из документации Microsoft, они классифицируются как
structs
, но почему CodeAnalyzer сообщает мне, что TypeKind является TypeKind.Class?
Вот некоторый контекст: в библиотеке, которую я пишу, классы анализируются для создания исходного кода (C # 9 Source Generator), который по существу использует .NetAnalyzer. Каждое из свойств класса будет проверяться, считается ли их тип классом. Оказывается
string?
считается классом.
2 ответа
В C # существует определенное ограничение для классов, допускающих значение NULL, поэтому с точки зрения ограничений во время компиляции
SomeRefType?
не совпадает
T:class
, но он будет соответствовать
T:class?
.
where T : class
Аргумент типа должен быть ссылочным типом. Это ограничение применяется также к любому типу класса, интерфейса, делегата или массива. В контексте, допускающем значение NULL, в C# 8.0 или более поздней версии T должен быть ссылочным типом, не допускающим значения NULL.
where T : class?
Аргумент типа должен быть ссылочным типом, допускающим или не допускающим значения NULL. Это ограничение применяется также к любому типу класса, интерфейса, делегата или массива.
Так что, возможно, в контексте, допускающем значение NULL, вы захотите использовать второй:
public class ReferenceEqualityComparer<T> : IEqualityComparer<T> where T : class?
Которая не даст никаких предупреждений ни для
string?
ни для
string
.
string
s являются классами и не могут использоваться в качестве аргумента универсального типа для
Nullable
из-за общего ограничения
where T : struct
. В вашем контексте
string?
- это , ссылочный типдопускающий значение NULL, который можно использовать для указания компилятору, что ссылочный тип не должен иметь в качестве значения (переменные по-прежнему могут иметь значение и должны проверяться на значения в общедоступных API, но компилятор предупредит вас, когда вы
null
в контексте, не допускающем значения NULL)