BT

最新技術を追い求めるデベロッパのための情報コミュニティ

寄稿

Topics

地域を選ぶ

InfoQ ホームページ ニュース C# 7.3の新機能

C# 7.3の新機能

ブックマーク

原文(投稿日:2018/05/18)へのリンク

読者の皆様へ:ノイズを減らすための一連の機能を開発しました。関心のあるトピックについて電子メールとWeb通知を受け取ることができます新機能の詳細をご覧ください。

比較的小さなリリースだが、C# 7.3はC# 1と2から長い間残った苦情に対応している。

Overload解決

バージョン1.0のC#から、overloadの解決ルールは、疑問の残るデザインであった。いくつかの状況で2つ以上のメソッドが候補になるが、1つしか使用できない。優先順位に基づき、正しくないメソッドが選択されるか、コンパイラーが一致するメソッドを見つけられない、または一致するがあいまいなことがある。

C# 7.3では、オーバーロード解決時にいくつかのチェックがされるため、誤った一致によるコンパイルエラーが発生しなくなった。改善されたoverload候補提案の概要:

1. インスタンスとstaticメンバーの両方が含まれている場合、インスタンスレシーバーかコンテキストなしで呼び出された場合はインスタンスメンバーを破棄し、インスタンスレシーバーがあって呼び出された場合はstaticメンバーを破棄する。レシーバーがない場合、staticコンテキストにstaticメンバーのみを含め、それ以外の時はstaticとインスタンスメンバーの両方を含める。レシーバーがインスタンスか型かがあいまいな時は、両方を含める。明らかにインスタンスレシーバーが使えないstaticコンテキストには、staticメンバーなどのメンバーの本体が定義されていないメンバー、フィールドイニシャライザとコンストラクターイニシャライザなど、これが使用できない場所が含まれる。

2. 型引数が制約を満たさないジェネリックメソッドは、候補セットから削除される。

3. メソッドグループの変換では、候補メソッドが、delegateの戻り型とマッチしない場合、セットから削除される。

ジェネリックの制約: enum, delegate, unmanaged

C# 2.0でジェネリクスが導入されて以来、開発者はenumがジェネリック型にできないことに不満を持っていた。これは最終的に対処され、enumキーワードをジェネリックとして使用できるようになった。同様にキーワードdelegateジェネリック制約に使用できるようになった。

これらは必ずしも期待通りに動作するわけではない。例えばwhere T : enum制約は、System.Enumのサブクラスとして使用したいだろうが、Foo<System.Enum>でも使用できる。とはいえ、enumとdelegateのほとんどのシナリオをカバーするはずである。

Unmanaged型制約は、“unmanaged”キーワードを使った場合、「参照型でなく、ネストのどのレベルでも参照型のフィールドが含まれていない型」である必要がある。 これは「すべてがアンマネージド型で再利用可能なルーチンを作る」必要がある場合の、低レベルなinteropコードで使用される。アンマネージド型には以下が含まれる:

  • プリミティブなsbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, bool, IntPtr, UIntPtr
  • あらゆるenum型
  • ポインター型
  • 上記のみが含まれるユーザー定義の構造体

隠しフィールドの属性

自動実装プロパティは非常に便利だが、後方のフィールドに属性を適用できないためそれを見ることができないなど、いくつかの制限がある。通常は問題にならないが、シリアライゼーションを扱うときに問題になることがある。

自動実装されたプロパティフィールドターゲット属性提案は、これをストレートに対処している。自動実装されたプロパティを適用するときは、シンプルにfield:修飾子を付与する。

[Serializable]
public class Foo {

    [field: NonSerialized]
    public string MySecret { get; set; }
}

タプル比較(== と !=)

タプル型で== と != をサポートする、この提案の名前は、詳細とエッジケースをうまく要約している。もっとも重要な変更点は

もし誰かが比較演算子を実装したValueTuple型を書いたとしたら、以前はoverload解決によって選ばれていた。しかし新しいタプルでは、overload解決よりも前に、ユーザー定義の比較に頼るのではなく、タプル比較が処理される。

理想としては、カスタムValueTuple型は、C# 7.3コンパイラーと同じルールに従うことだが、ネストされたタプルやdynamic型の処理で微妙な違いが発生する。

イニシャライザの式変数

これはアンチ機能のように見える。機能を追加するのではなく、Microsoftは式変数が使用できる場所の制限を取り除いた。

ctor-initializer内の式変数宣言(out変数宣言と宣言パターン)を禁止する制限を削除した。宣言された変数は、コンストラクタのボディで有効になる。

フィールドまたはプロパティイニシャライザ内の式変数宣言(out変数宣言と宣言パターン)を禁止する制限を削除した。宣言された変数は、イニシャライザ式内で有効になる。

lambdaのボディに変換されるクエリ式内の変数式宣言(out変数宣言と宣言パターン)を禁止する制限を削除した。宣言された変数は、クエリの式内で有効になる。

これらの制限の当初の理由は、単に「時間の不足」を書かれていた。おそらくこの制限により、C# 7の以前のバージョンで必要だったテスト量が削減されたと考えられる。

スタックに割り当てられた配列

まれにしか使われないが、重要なC#の機能は、stackallocキーワードでスタック内に割り当てられる配列である。これにより、ヒープへの割り当てとGCの圧迫が起こらないことで、通常の配列はパフォーマンが改善する可能性がある。

int* block = stackalloc int[3] { 1, 2, 3 };

スタックに割り当てられた配列を使うことは危険なことがある。スタックに対応するポイントが必要になった時に、unsafeコンテキストの中でしか使用できない。CLRは、バッファオーバーランを有効にすることで、これを軽減しようとしている。これにより、アプリケーションは「可能な限り迅速に終了する」ようになる。

C# 7.3では、通常の配列と同様に、作成するときに配列を初期化できる。この提案には詳細がないが、Microsoftは機能が実行されたときに迅速にコピーできるマスター配列を事前初期化することを検討している。理論上は、要素ごとに初期化するよりも早くなる。

注意点として、スタックに割り当てられた配列は、多くの小さな、短期の配列が必要なシナリオを対象にしている。大きな配列や、深く再帰的な関数に使用すると、スタック領域を超える可能性があるため、使用してはならない。

スタックに割り当てられたSpan

スタックに割り当てられた配列の安全な代替は、スタックに割り当てられたspanである。ポインターを削除することで、バッファオーバーランも削除できる。これにより、メソッドをunsafeにしなくても使用できる。

Span<int> block = stackalloc int[3] { 1, 2, 3 };

注意点としてSpan<T>は、System.Memory NuGetパッケージが必要になる。

再割り当て可能なRefローカル

Refローカルは、通常のローカル変数のように再アサイン可能になった。

他のC# 7.3提案は、csharplang GitHubサイトを参照して欲しい。

 
 

Rate this Article

Adoption Stage
Style
 
 

この記事に星をつける

おすすめ度
スタイル

BT