Skip to content

Commit a79d87f

Browse files
author
y-yamasaki
committed
ブログ追加
1 parent 1b8e4af commit a79d87f

1 file changed

Lines changed: 167 additions & 0 deletions

File tree

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
---
2+
title: C#14の新機能の解説
3+
date: 2025-12-12
4+
category: C#
5+
description:
6+
tags: [Gemini, Copilot, API]
7+
recommended: true
8+
thumbnail: assets/img/gemini_icon.png
9+
---
10+
11+
こんにちは!パン君です。
12+
13+
今回は先月末に公開された C#14 のドキュメントからいくつか機能をピックアップして紹介しようと思います。
14+
公式はこちら
15+
[!CARD](https://learn.microsoft.com/ja-jp/dotnet/csharp/whats-new/csharp-14)
16+
17+
# field キーワード
18+
19+
よくフィールドとプロパティを利用して下記のような記述を多様する方がいるかと思います。
20+
これの目的はご存知の通り カプセル化が主な目的です。
21+
これが今回の新機能で下記のように記述が可能になりました。
22+
23+
```csharp
24+
// before
25+
private string m_foo;
26+
public string Foo
27+
{
28+
get => m_foo;
29+
private set => m_foo = value;
30+
// nullチェックを入れたかったら
31+
// ?? throw new ArgumentNullException(nameof(value))
32+
}
33+
34+
// after
35+
public string Foo
36+
{
37+
get;
38+
set => field = value;
39+
}
40+
```
41+
42+
IntelliSenseがあるIDE利用者とかは `m_` と入力して予測補完させる人とか多いはずなので、正直コードの組み方次第な機能ですね
43+
Regionとかでくくったり、可読性など気にしていたり、
44+
IntelliSense前提のコーディングをしていない人とかなら良いのかも?
45+
46+
まぁそもそもちゃんとしたコード規約の元作られているプロジェクトでの作業前提ではありますが、、、  
47+
48+
一応このシンボルと重複した命名があるときの対処法もドキュメントは追記してくれています。
49+
がしかし、それより先に`field`っていう命名を見つけたら`git blame`で特定してその人を警戒するようにしましょう。
50+
51+
> fieldという名前のシンボルを含む型のコードを読み取る場合、破壊的変更や混乱が生じる可能性があります。
52+
> @fieldまたはthis.fieldを使用して、field キーワードと識別子の間であいまいさを解消したり、
53+
> 現在のfieldシンボルの名前を変更して区別を深めることができます。
54+
55+
[!CARD](https://learn.microsoft.com/ja-jp/dotnet/csharp/whats-new/csharp-14#the-field-keyword)
56+
57+
# 拡張メンバー
58+
59+
よく引き数に `this ClassName valueName` と記述するあれですね
60+
61+
```csharp
62+
public class Foo
63+
{
64+
public int hoge = 1;
65+
}
66+
67+
// before
68+
public static class FooExtensions
69+
{
70+
public static int BeforeExtension(this Foo foo) => foo.hoge;
71+
}
72+
73+
// after
74+
public static class FooExtensions
75+
{
76+
extension(Foo foo)
77+
{
78+
public int AfterExtension() => foo.hoge;
79+
}
80+
}
81+
```
82+
83+
メリットは
84+
85+
- 毎回引き数にインスタンスを渡す場所の明記がいらなくなった
86+
- extension ブロック内に記述すればいいので、視覚的に優しくなった
87+
- 拡張プロパティも宣言可能
88+
- 拡張オペレーターの宣言も可能
89+
90+
他詳細は下記の公式参照
91+
[!CARD](https://learn.microsoft.com/ja-jp/dotnet/csharp/whats-new/csharp-14#extension-members)
92+
93+
# Null 条件付き割り当て
94+
95+
```csharp
96+
public Class Hoge
97+
{
98+
public string? Name = { get; set; } = null;
99+
}
100+
101+
void string GetName() => "Pankun";
102+
103+
void Foo(Hoge? hoge)
104+
{
105+
// before
106+
if(hoge is not null) // Null check can be simplified (IDE0031)
107+
hoge.Name = GetName();
108+
109+
// after
110+
hoge?.Name = getName();
111+
}
112+
```
113+
114+
メリットは
115+
116+
- ネスト節約
117+
- 上に続いて可読性向上
118+
119+
# Partialメンバー
120+
121+
```csharp
122+
// Foo.cs
123+
public partial class Foo
124+
{
125+
// コンストラクター実装
126+
public partial Foo()
127+
{
128+
Hoge();
129+
}
130+
131+
// メンバ関数追加
132+
private partial void Hoge() => Console.WriteLine("Partial Hoge");
133+
}
134+
135+
// Foo.members.cs
136+
public partial class Foo
137+
{
138+
// ここで宣言だけ追加が可能
139+
// コンストラクター対応
140+
// staticは対応していません
141+
public partial Foo(); // Success
142+
private partial void Hoge(); // Success
143+
}
144+
```
145+
146+
これで 「これ定義無いけどなんで呼べているんだ?」 とならなくて済みます。
147+
148+
149+
# nameofが未バインドジェネリック型に対応
150+
151+
```csharp
152+
public static void ShowExample()
153+
{
154+
// Before
155+
Console.WriteLine(nameof(List<int>)); // List<int>
156+
157+
// After
158+
// nameof する引数はバインドされていないジェネリック型にすることができます。
159+
Console.WriteLine(nameof(List<>)); // List
160+
// NOTE: Use unbound generic type (IDE0340) の警告が出ます。
161+
Console.WriteLine(nameof(List<int>)); // List<int>
162+
}
163+
```
164+
165+
これにより幅広く判定が取れるようになりました
166+
167+
#

0 commit comments

Comments
 (0)