C# の GitHub ページには数多くの魅力的なアイデアが列挙されており、いくつかの頭の痛い問題についてはまだ議論が続いている。C# 10 に実際にどのような新機能が含まれているのか知りたければ、11月の新バージョンのリリースを待つのも一つの手だ。あるいは、C# チームが気に入っている機能を紹介するのをフォローするのも良い。最近の Microsoft Build カンファレンスで、C# のチーフデザイナーである Mads Torgersen は現在進行中の作業の一部を明かした。以下は、この言語の次のバージョンで提供される5大新機能である。

1. global using
C# のソースコードファイルは、通常、冒頭で大量の名前空間をインポートする。以下は、一般的な ASP.NET Web アプリケーションのコードスニペットである。
using LoggingTestApp.Data;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace LoggingTestApp
{
public class Startup
{
...
}
}
このコードの書き方に特に特別な点はない。以前は、名前空間のインポートによって、あるクラスがどのライブラリを使用しているかを素早く把握することができた。しかし今日では、これは書かざるを得ないだけで誰も見ないコードの山に過ぎない。
C# 10 では、キーワード global を使用してプロジェクト全体の名前空間インポートを定義できる新しいモードが導入された。推奨される方法は、グローバルインポートを別のファイル(プロジェクトごとに1つ)に置くことで、usings.cs や imports.cs と名前を付けることができる。その内容はおおよそ次のようになる。
global using Microsoft.AspNetCore.Builder;
global using Microsoft.AspNetCore.Hosting;
global using Microsoft.AspNetCore.HttpsPolicy;
global using Microsoft.AspNetCore.Identity;
global using Microsoft.AspNetCore.Identity.UI;
global using Microsoft.EntityFrameworkCore;
global using Microsoft.Extensions.Configuration;
global using Microsoft.Extensions.DependencyInjection;
global using Microsoft.Extensions.Hosting;
global using System;
global using System.Collections.Generic;
global using System.Linq;
global using System.Threading.Tasks;
すると、元のファイルは次のように簡略化できる。
using LoggingTestApp.Data;
using Serilog;
namespace LoggingTestApp
{
public class Startup
{
...
}
}
Visual Studio は重複する名前空間(グローバルファイルとローカルファイルの両方でインポートされている名前空間)を強調表示する。これはエラーではないが、重複する名前空間を削除することでコード量を減らし、特定のファイルで使用されている特別な名前空間に注意を集中させることができる。
2. ファイルスコープの名前空間
C# 10 では、コードを簡略化する別の方法として、ファイルスコープの名前空間を宣言できる。ファイルスコープの名前空間は自動的にファイル全体に適用され、インデントが不要になる。
言い換えれば、次のような書き方
namespace LoggingTestApp
{
public class Startup
{
...
}
}
は次のようになる。
namespace LoggingTestApp;
public class Startup
{
...
}
ファイルスコープの名前空間を使用しているファイル内にさらに名前空間ブロックを追加すると、入れ子の名前空間が作成される。
namespace Company.Product;
// このブロックは名前空間 Company.Product.Component を作成する
namespace Component
{
}
C# の設計者は、この変更によって水平方向のスペースの無駄が削減されると考えている(global using が垂直方向のスペースの無駄を削減したのと同様に)。全体的な目標は、コードをより短く、より狭く、より簡潔にすることだ。しかし、これらの変更は初心者が C# を学ぶ難易度を下げることにもなる。global using とファイルスコープの名前空間を組み合わせれば、わずか数行のコードで Hello World コンソールアプリケーションを作成できる。
3. null 引数チェック
ボイラープレートコード削減の精神に則り、C# は非常に便利な新機能、null 引数チェックを提供する。null チェックが必要なメソッドを書いたことがあるだろう。例えば、次のようなコードだ。
public UpdateAddress(int personId, Address newAddress)
{
if (newAddress == null)
{
throw new ArgumentNullException("newAddress");
}
...
}
今では、パラメータ名の末尾に「!!」を追加するだけで、C# が自動的にこの null 引数チェックを挿入してくれる。上記のコードは次のように簡略化できる。
public UpdateAddress(int personId, Address newAddress!!)
{
...
}
これで、Address に null 値が渡されると、自動的に ArgumentNullException がスローされる。
このような細かい点は取るに足らないように思えるかもしれないが、実際にはこれは非常に簡単でありながら価値のある言語最適化の方法である。多くの研究が示すように、プログラムのエラーの原因は、コード内の概念が複雑すぎるからではなく、コードを読むのに疲れ、人間の注意力には限りがあるために、非常に回避しやすいミスが繰り返し発生することにある。コード量を減らすことで、コードレビューに必要な時間、コード処理に必要な認知負荷、注意力低下によってミスを見逃す可能性を減らすことができる。
4. required 属性
以前は、オブジェクトの正しい作成を保証するには、クラスコンストラクターを使うしかなかった。今日では、以下のレコードにある自動実装プロパティのような、より軽量な構造がよく使われる。
public record Employee
{
public string Name { get; init; }
public decimal YearlySalary { get; init; }
public DateTime HiredDate{ get; init; }
}
このような軽量オブジェクトのインスタンスを作成する際には、オブジェクト初期化子を使用することがある。
var theNewGuy = new Employee
{
Name = "Dave Bowman",
YearlySalary = 100000m,
HiredDate = DateTime.Now()
};
しかし、オブジェクトの一部のプロパティが必須である場合はどうすればよいだろうか?これまでと同じようにコンストラクターを追加することもできるが、そうするとさらにボイラープレートコードが増える。また、パラメーターからプロパティに値をコピーする処理も、理解は容易だがよくあるエラーの原因となる。
C# 10 で導入されたキーワード required は、このような問題を解消する。
public record Employee
{
public required string Name { get; init; }
public decimal YearlySalary { get; init; }
public DateTime HiredDate{ get; init; }
}
これにより、Name プロパティを設定しなければ Employee を作成できなくなる。
5. キーワード field
長年にわたり、C# チームは自動実装プロパティによるコード簡略化に多大な努力を払ってきた。上の Employee レコードはその良い例で、get と init キーワードを使用して3つの不変プロパティを宣言している。データは3つのプライベートフィールドに格納されるが、これらのフィールドは自動的に作成され、手動での介入は不要である。そして、それらのフィールドを目にすることは決してない。
自動実装プロパティは素晴らしいが、その機能は限られている。自動実装プロパティが使えない場合、クラスにバッキングフィールドを追加し、通常のプロパティメソッドを記述する必要があり、まるで C# 2 に戻ったかのようになる。しかし、C# 10 ではキーワード field が提供され、自動的にバッキングフィールドを作成できる。
例えば、初期プロパティ値を処理するレコードを作成したいとする。以下のコードでは、Employee クラスに若干の修正を加え、HiredDate フィールドが DateTime オブジェクトの日付情報のみ(時刻情報は含まない)を含むことを保証している。
public record Employee
{
public required string Name { get; init; }
public decimal YearlySalary { get; init; }
public DateTime HiredDate{ get; init => field = value.Date(); }
}
このコードは非常に簡潔で、シンプルであり、宣言的なスタイルに近い。
キーワード field を使用して、get、set、init 内のフィールドにアクセスできる。また、通常のクラスのプロパティと同様に、プロパティの検証が必要になるかもしれない。
private string _firstName;
public string FirstName
{
get
{
return _firstName;
}
set
{
if (value.Trim() == "")
throw new ArgumentException("No blank strings");
_firstName = value;
}
}
この検証を、field を使って自動実装プロパティにも適用できる。
public string FirstName {get;
set
{
if (value.Trim() == "")
throw new ArgumentException("No blank strings");
field = value;
}
}
本質的には、プロパティのデータ型を変更する必要がない限り、自分でバッキングフィールドを宣言する必要はない。
6. まとめ
もちろん、C# 10 の新機能はこれら5つだけではない。式に関する変更や、インターフェース内での静的メンバーの定義という議論を呼ぶ変更もある。我々は辛抱強く待つしかない。
全体的に見ると、C# 10 の開発の重点は明確であり、コード量の削減、利便性の向上、開発者の負担軽減である。
原文著者:Matthew MacDonald
原文リンク:https://medium.com/young-coder/a-closer-look-at-5-new-features-in-c-10-f99738b0158e
翻訳者:弯月
編集者:欧阳姝黎
発行:CSDN(ID:CSDNnews)
声明:本記事は CSDN による翻訳であり、出典を明記して転載すること。