C# Linq Joinによる結合元のデータ更新方法
例えば以下のようなコードがあるとします。

```

    public class Employee
        {
            public string Name { get; set; }
            public int JobId { get; set; }
            public string JobName { get; set; }
        }
    
        public class Job
        {
            public int JobId { get; set; }
    
            public string JobName { get; set; }
        }
    
        public void DoTest()
        {
            var employees = new List<Employee>();
            employees.Add(new Employee() { Name = "John", JobId = 1 });
            employees.Add(new Employee() { Name = "Danny", JobId = 2 });
            employees.Add(new Employee() { Name = "Ashley", JobId = 2 });
            employees.Add(new Employee() { Name = "Taro", JobId = 3 });
    
            var jobs = new List<Job>();
            jobs.Add(new Job() { JobId = 1, JobName = "Database Engineer" });
            jobs.Add(new Job() { JobId = 2, JobName = "Designer" });
            jobs.Add(new Job() { JobId = 3, JobName = "Manager" });
            jobs.Add(new Job() { JobId = 4, JobName = "Network Engineer" });
    
            var query = from em in employees
                        join j in jobs on em.JobId equals j.JobId
                        select new Employee() { Name = em.Name, JobId = em.JobId, JobName = j.JobName };
    
        }
    
```

最後のjoin句後にselect句でnewをし、Emplyeeクラスのインスタンスを生成しています。

私は **emplyeesに含まれる各インスタンスのJobNameのみを更新したい** のですが、その場合、どのように書くのが良いでしょうか。  
このコードではselect句後にnewしているので、レコードが多い場合、インスタンス生成にメモリを奪われる、または  
EmployeeインスタンスのJobNameだけを更新したいのに、newするときに各パラメータを指定し直しているため、パラメータが多い場合にコード量が多くなることを懸念しています。
C# 9.0（.NET 5.0）だとレコードが追加されます。レコードには[`with`式](https://docs.microsoft.com/ja-
jp/dotnet/csharp/language-reference/operators/with-
expression)というものがあり、指定したプロパティだけ書き換わった新しいインスタンスを作成できます。これを使うと次のように書けます。

```

    public record Employee {
        public string Name { get; init; }
        public int JobId { get; init; }
        public string JobName { get; init; }
    }
    
    public record Job {
        public int JobId { get; init; }
        public string JobName { get; init; }
    }
    
    public void DoTest() {
        var employees = new List<Employee> {
            new Employee { Name = "John", JobId = 1 },
            new Employee { Name = "Danny", JobId = 2 },
            new Employee { Name = "Ashley", JobId = 2 },
            new Employee { Name = "Taro", JobId = 3 },
        };
        var jobs = new List<Job> {
            new Job { JobId = 1, JobName = "Database Engineer" },
            new Job { JobId = 2, JobName = "Designer" },
            new Job { JobId = 3, JobName = "Manager" },
            new Job { JobId = 3, JobName = "Network Engineer" },
        };
    
        var query = from em in employees
                    join j in jobs on em.JobId equals j.JobId
                    select em with { JobName = j.JobName };
    }
    
```

* * *

> レコードが多い場合、インスタンス生成にメモリを奪われる

懸念はごもっともです。ただし、Employeeインスタンスと同数のName文字列が必要ですので、Employeeだけを考慮していても仕方がありません。  
もしEmployeeインスタンスが膨大でパフォーマンスに支配的な影響を与える場合は、値型への変更なども視野に入ってきます。値型であればGC管理不要で、配列や`List<T>`が連続した大きな領域を確保するだけとなります。

* * *

.NET 6 / C# 10がリリースされました。C#
10では、`with`式が拡張され、レコード以外に構造体や匿名型にも適用できるようになりました。また、レコードも拡張されレコード構造体も定義できるようになりました。
C# 9.0（.NET 5.0）だとレコードが追加されます。レコードには[`with`式](https://docs.microsoft.com/ja-
jp/dotnet/csharp/language-reference/operators/with-
expression)というものがあり、指定したプロパティだけ書き換わった新しいインスタンスを作成できます。これを使うと次のように書けます。

```

    public record Employee {
        public string Name { get; init; }
        public int JobId { get; init; }
        public string JobName { get; init; }
    }
    
    public record Job {
        public int JobId { get; init; }
        public string JobName { get; init; }
    }
    
    public void DoTest() {
        var employees = new List<Employee> {
            new Employee { Name = "John", JobId = 1 },
            new Employee { Name = "Danny", JobId = 2 },
            new Employee { Name = "Ashley", JobId = 2 },
            new Employee { Name = "Taro", JobId = 3 },
        };
        var jobs = new List<Job> {
            new Job { JobId = 1, JobName = "Database Engineer" },
            new Job { JobId = 2, JobName = "Designer" },
            new Job { JobId = 3, JobName = "Manager" },
            new Job { JobId = 3, JobName = "Network Engineer" },
        };
    
        var query = from em in employees
                    join j in jobs on em.JobId equals j.JobId
                    select em with { JobName = j.JobName };
    }
    
```

* * *

> レコードが多い場合、インスタンス生成にメモリを奪われる

懸念はごもっともです。ただし、Employeeインスタンスと同数のName文字列が必要ですので、Employeeだけを考慮していても仕方がありません。  
もしEmployeeインスタンスが膨大でパフォーマンスに支配的な影響を与える場合は、値型への変更なども視野に入ってきます。値型であればGC管理不要で、配列や`List<T>`が連続した大きな領域を確保するだけとなります。

* * *

.NET 6 / C# 10がリリースされました。C#
10では、`with`式が拡張され、レコード以外に構造体や匿名型にも適用できるようになりました。また、レコードも拡張されレコード構造体も定義できるようになりました。