You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

LINQ延迟执行时属性更新失效及无空引用异常的原因问询

问题解答

代码重现

#nullable enable

using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
    public static void Main()
    {
        var userNames = new List<string>{"Jon Doe", "Jane Doe"};
        var persons = userNames.Select(x => new Person{ Name = x });
        
        foreach (var person in persons)
        {
            person.FamilyName = person.Name.Split(' ').Last();
        }

        var familyNameList = persons.Select(x => x.FamilyName).ToList();
        Console.WriteLine(string.Join(", ", familyNameList));
    }

    private class Person
    {
        public required string Name { get; init; }

        public string? FamilyName { get; set; }
    }
}

#nullable disable

控制台输出

, 

问题1:foreach中设置的FamilyName为何未生效?

LINQ的Select操作是延迟执行的,它不会立即生成结果集合,而是在每次遍历(比如foreach、ToList())时才会执行传入的委托逻辑(也就是new Person{ Name = x })。

这里的核心问题是:

  • 第一次遍历persons(foreach循环)时,会为每个userNames元素创建一个Person实例,并设置其FamilyName,但这些实例在遍历结束后就被丢弃了,没有被保存下来。
  • 第二次调用persons.Select(...).ToList()时,会重新遍历userNames,再次创建全新的Person实例,这些新实例的FamilyName从未被设置过,自然都是null,所以最终输出两个null拼接的结果。

解决办法:在第一次遍历前,把persons转换成立即执行的集合(比如调用ToList()),这样后续操作都基于同一个实例集合:

var persons = userNames.Select(x => new Person{ Name = x }).ToList();

问题2:为何设置FamilyName时未抛出NullReferenceException?

延迟执行不等于“不创建实例”——当你执行foreach (var person in persons)时,已经触发了Select委托的执行,每个循环迭代都会创建一个Person实例,所以person变量是有效的非空引用,设置它的FamilyName属性自然不会抛出空引用异常。

只是这些实例在foreach循环结束后没有被保留,后续第二次遍历persons时又生成了新的实例而已。


内容的提问来源于stack exchange,提问作者Pelle Stenild Coltau

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 21:55:24