Тип 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.

strings являются классами и не могут использоваться в качестве аргумента универсального типа для Nullable из-за общего ограничения where T : struct. В вашем контексте string?- это , ссылочный типдопускающий значение NULL, который можно использовать для указания компилятору, что ссылочный тип не должен иметь в качестве значения (переменные по-прежнему могут иметь значение и должны проверяться на значения в общедоступных API, но компилятор предупредит вас, когда вы null в контексте, не допускающем значения NULL)

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