Почему этот код C# возвращает исключение нулевой ссылки без предупреждения?C#

Место общения программистов C#
Ответить
Anonymous
 Почему этот код C# возвращает исключение нулевой ссылки без предупреждения?

Сообщение Anonymous »

Насколько я понимаю, функции защиты от нулевых значений в C# (начиная с C# 8.0 и далее) заключаются в том, что (возможно) нулевые переменные должны быть типизированы как допускающие значение NULL, и что компилятор статически обнаруживает любые части кода, которые могут включать разыменование нулевой ссылки, и выдает предупреждение. В сочетании с Nullable я ожидаю, что это сделает невозможным возникновение исключений нулевых ссылок.
Однако следующий код компилируется, но когда запрос Get отправляется в /endpoint, он возвращает исключение нулевой ссылки:

Код: Выделить всё

using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

var connString = "User ID=postgres;Password=password;Host=localhost;Port=5432;Pooling=true;Connection Lifetime=0;Database=MinExample";
builder.Services.AddDbContext(options => options.UseNpgsql(connString));
var app = builder.Build();

app.MapGet("/endpoint", long (AppDbContext context) =>
{
var id = new Service(context).GetBId();
return id;
});

app.Run();

public record A
{
public long AId { get; init; }
public required B B { get; set; }
}

public class B
{
public required long BId { get; init; }
}

public class Service
{
private readonly AppDbContext _context;
public Service(AppDbContext cx)
{
_context = cx;
}

public long GetBId()
{
var a = _context.A.First();
return a.B.BId;
}
}

public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions options)
: base(options) { }
public DbSet A { get; set; }

}
Моя база данных имеет одну запись в таблице A и одну связанную запись в таблице B.
На самом деле компилятор настолько уверен, что id не равен нулю, что если я вставлю Console.WriteLine(id is null) непосредственно перед оператором возврата API, компилятор выдаст ошибку «Невозможно преобразовать значение null в «long», поскольку это тип значения, не допускающий значения NULL. С другой стороны, Console.WriteLine(id == null) компилируется и работает нормально (и записывает True в консоль), хотя JetBrains предупреждает меня, что результат выражения всегда имеет значение «false», поскольку значение типа «long» никогда не равно «null» типа «long»?
Почему компилятор не выдает мне ошибку о том, что возвращаемая переменная равна нулю? Является ли это нарушением безопасности? Что мне не хватает в том, как работает нулевая безопасность в C# 8.0 и более поздних версиях?
(«Решение» этой проблемы — заменить запрос на var a = _context.A.Include(a => a.B).First();, но мой вопрос заключается в том, почему компилятор не обнаруживает, что что-то не так, а не в том, как исправить проблему самостоятельно).
Все вышеперечисленное было построено с версией dotnet 9.0.112.

Подробнее здесь: https://stackoverflow.com/questions/798 ... ut-warning
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»