web-dev-qa-db-ja.com

C#7タプルとラムダ

新しいc#7タプル構文では、パラメーターとしてラムダを指定し、ラムダ内でアンパックされた値を使用できますか?

例:

var list = new List<(int,int)>();

ラムダでタプルを使用する通常の方法:

list.Select(value => value.Item1*2 + value.Item2/2);

.Item1.Item2、 好む:

list.Select((x,y) => x*2 + y/2);

最後の行は、ラムダの2つのパラメーターとして扱われるため機能しません。実際にそれを行う方法があるかどうかはわかりません。

編集:

ラムダ定義で二重括弧を試しましたが、うまくいきませんでした:((x,y)) => ...、そして多分それは試してみるのは愚かだったが、二重括弧は実際にここで動作します:

list.Add((1,2));

また、私の質問は、見苦しいデフォルト名を避けることではありません.Item .Item2、それは実際にラムダでタプルをアンパックすることに関するものです(そしておそらく実装されていないか不可能な理由です)。デフォルト名の解決策を求めてここに来た場合は、 Sergey Berezovskiy's answer を読んでください。

編集2:

より一般的なユースケースを考えてみてください:メソッドに渡されたタプルを「分解」することは可能ですか(または不可能です)?このような:

void Foo((int,int)(x,y)) { x+y; }

これの代わりに:

void Foo((int x,int y) value) { value.x+value.y }
55
Rast

あなたが観察したように、:

_var list = new List<(int,int)>();
_

少なくとも次のことができると期待されます。

_list.Select((x,y) => x*2 + y/2);
_

しかし、C#7コンパイラは(まだ)これをサポートしていません。また、次のことを可能にする砂糖を求めることも合理的です。

_void Foo(int x, int y) => ...

Foo(list[0]);
_

コンパイラがFoo(list[0]);Foo(list[0].Item1, list[0].Item2);に自動的に変換します。

現在、これらのどちらも不可能です。ただし、GitHubの_dotnet/csharplang_リポジトリに問題 提案:ラムダ引数リストのタプル分解 が存在し、言語チームがこれらの機能をC#の将来のバージョンで検討することを要求しています。このスレッドのサポートも見たい場合は、そのスレッドに声を追加してください。

30
David Arno

Tupleプロパティの名前を指定する必要があります(まあ、ValueTupleにはフィールドがあります)。そうしないと、デフォルトの名前が使用されます。

var list = new List<(int x, int y)>();

Tupleには、使用できる適切な名前のフィールドがあります

list.Select(t => t.x * 2 + t.y / 2)

NuGetからSystem.ValueTupleパッケージを追加することを忘れないでください。ValueTuplesは可変構造体であることに注意してください。


更新:現在、分解は、既存の変数への割り当て(deconstructon-assignment)または新しく作成されたローカル変数(deconstruction-declaration)としてのみ表されています。適用可能な関数メンバー選択アルゴリズムは以前と同じです:

引数リストの各引数は、7.5.1.1で説明されている関数メンバー宣言のパラメーターに対応し、引数が対応しないパラメーターはオプションのパラメーターです。

タプル変数は単一の引数です。メソッドの仮パラメータリストのいくつかのパラメータに対応することはできません。

26

C#7.0の分解では、3つの形式がサポートされています。

  • deconstruction-declaration(_(var x, var y) = e;_など)、
  • 分解割り当て(_(x, y) = e;_など)、
  • およびdeconstruction-foreach(foreach(var(x, y) in e) ...など)。

他のコンテキストも検討されましたが、実用性が低下している可能性が高いため、C#7.0の時間枠でそれらを完了できませんでした。 let句(let (x, y) = e ...)およびラムダの解体は、将来の拡張に適しているようです。

後者は https://github.com/dotnet/csharplang/issues/258 で議論されています

チャンピオンの提案に役立つので、フィードバックと関心を表明してください。

design doc のC#7.0分解に含まれるものの詳細。

7
Julien Couvreur

実行しているプログラムは、コンパイラがこの式の型を推測できないことです。

list.Select(((int x, int y) t) => t.x * 2 + t.y / 2);

しかしそれ以来 (int, int)および(int x, int y)は同じCLRタイプ(System.ValueType<int, int>)、タイプパラメータを指定する場合:

list.Select<(int x, int y), int>(t => t.x * 2 + t.y / 2);

それが動作します。

3
Paulo Morgado