我准备了一个简单的C# Fiddle,它调用an OSRM map matching service URL并解析JSON响应.

我的问题是,有一条生产线生产warning CS8602: Dereference of a possibly null reference:

if (osrmResponse?.code == "Ok" && osrmResponse.matchings != null)
{
    return osrmResponse.matchings
        .Where(matching => matching != null)
        .SelectMany(matching => matching.legs ?? Enumerable.Empty<Leg>())
        .Where(leg => leg != null && leg.annotation != null && leg.annotation.nodes != null)
        // How to fix dereference of a possibly null value in the next line?
        .SelectMany(leg => leg.annotation.nodes ?? Enumerable.Empty<long>())
        // eliminate duplicate node ids by converting to an ISet
        .ToHashSet()
        .ToList();
}

我不明白,如果我在有问题的行之前判断.Where中的调用,为什么编译器认为legleg.annotaion为空?

原因可能是.Where()呼叫的签名,然后如何解决呢?

完整的测试用例复制如下:

namespace OsrmMapMatch
{
    public class OsrmResponse
    {
        public string? code { get; set; }
        public Matching[]? matchings { get; set; }
    }

    public class Matching
    {
        public Leg[]? legs { get; set; }
    }
    public class Leg
    {
        public Annotation? annotation { get; set; }
    }

    public class Annotation
    {
        public long[]? nodes { get; set; }
    }

    internal class Program
    {
        const string OsrmUri = "?overview=simplified&generate_hints=false&skip_waypoints=true&gaps=ignore&annotations=nodes&geometries=geojson&radiuses=";

        readonly static (double lng, double lat)[] Locations = 
        {
            (10.757938, 52.437444),
            (10.764379, 52.437314),
            (10.770562, 52.439067),
            (10.773268, 52.436633),
        };

        static async Task Main(string[] args)
        {
            const string HttpClientMapMatch = "HttpClientMapMatch";

            ServiceProvider serviceProvider = new ServiceCollection()
                .AddHttpClient(HttpClientMapMatch, httpClient =>
                {
                    httpClient.BaseAddress = new Uri("https://router.project-osrm.org/match/v1/driving/");
                }).Services.BuildServiceProvider();

            IHttpClientFactory? httpClientFactory = serviceProvider.GetService<IHttpClientFactory>();
            HttpClient? httpClient = httpClientFactory?.CreateClient(HttpClientMapMatch);
            if (httpClient == null)
            {
                Console.WriteLine("Error httpClient is null");
                return;
            }

            IEnumerable<long> nodes = await GetOsmNodesAsync(httpClient, Locations);
            Console.WriteLine($"Map matched OSM node ids: {JsonSerializer.Serialize(nodes.OrderBy(node => node))}\n");
        }

        private static async Task<IEnumerable<long>> GetOsmNodesAsync(HttpClient httpClient, IEnumerable<(double lng, double lat)> locations)
        {
            IEnumerable<string> lngLats = locations
                .Select(location => $"{location.lng:F6},{location.lat:F6}")
                .ToList();

            IEnumerable<int> radiuses = locations
                .Select(location => 50)
                .ToList();

            string requestUri = string.Join(";", lngLats) + OsrmUri + string.Join(";", radiuses);
            OsrmResponse? osrmResponse = await httpClient.GetFromJsonAsync<OsrmResponse>(requestUri);
            if (osrmResponse?.code == "Ok" && osrmResponse.matchings != null)
            {
                return osrmResponse.matchings
                    .Where(matching => matching != null)
                    .SelectMany(matching => matching.legs ?? Enumerable.Empty<Leg>())
                    .Where(leg => leg != null && leg.annotation != null && leg.annotation.nodes != null)
                    // How to fix dereference of a possibly null value in the next line?
                    .SelectMany(leg => leg.annotation.nodes ?? Enumerable.Empty<long>())
                    // eliminate duplicate node ids by converting to an ISet
                    .ToHashSet()
                    .ToList();
            }

            return Enumerable.Empty<long>();
        }
    }
}

推荐答案

当前的链接器无法分析每条可能的执行路径,因此此链接器正在检测可能的空解引用的误报.

在这种情况下,你的RI(真正的智力)是最好的.

该语言提供了一种机制,即null forgiving operator,以避免这种林特警告.

如果不使用允许空值的运算符,编译器将生成 前面代码的以下警告:警告CS8625:无法 将Null文本转换为不可为Null的引用类型.通过使用 允许空值的运算符,则通知编译器传递空值是 这是意料之中的,不应该被警告.

在此申请:

leg!.annotation!.nodes

Csharp相关问答推荐

访问C#中的数据库字段时获取数据是收件箱错误-为什么?&有效,如果声明不有效

当MD5被废弃时,如何在Blazor WASM中使用它?

如何禁用ASP.NET MVP按钮,以便无法使用开发人员控制台重新启用它

Dapper是否可以自动扩展类成员

Monty Hall游戏节目模拟给我50/50的结果

Azure DEVOPS找不到定制的Nuget包

静态对象构造顺序

MS Graph v5.42.0:在寻呼消息时更改页面大小

集合表达式没有目标类型

Lambda表达式如何与隐式强制转换一起工作?

在.NET 8最低API中从表单绑定中排除属性

是否可以将Collectionview中的数组与ObservableCollection绑定?

.NET 6:如何防止系统生成的日志(log)?

在Windows Plesk上发布ASP.NET Core 7 Web API-错误:无法加载文件或程序集';Microsoft.Data.SqlClient';

如何在同一成员上组合[JsonPropertyName]和[ObservableProperty]?

Blazor Server/.NET 8/在初始加载时调用异步代码是否冻结屏幕,直到第一次异步调用完成?

C#中使用ReadOnlySpan的泛型类型推理

如何保存具有多个重叠图片框的图片框?

反序列化我以前使用System.Text.Json序列化的文件时出现异常

为什么C#中的类型别名不能在另一个别名中使用?