タプルが解決するために設計された要件は何ですか?


94

タプルの新しいC#機能を見ています。気になるのですが、タプルが解決するために設計された問題は何ですか?

アプリでタプルを何に使用しましたか?

更新

これまでの回答に感謝します。頭の中で真っ直ぐになっているかどうか確認してみましょう。タプルの良い例が座標として指摘されています。これは正しく見えますか?

var coords = Tuple.Create(geoLat,geoLong);

次に、タプルを次のように使用します。

var myLatlng = new google.maps.LatLng("+ coords.Item1 + ", "+ coords.Item2 + ");

あれは正しいですか?



4
まあ、私は2つの答えを考えることができます...
正午シルク

13
「コーディネート」という概念がクラスとして理にかなっているとしたら、私はそれをクラスにしたいと思います。タプルは、型の作成を正当化するデータのセットに適切な「ビジネスロジック」の概念がない状況で使用します。
Eric Lippert、2010年

13
座標はタプルの良い例ではありません。C#のタプルは、(関数から)2つの値を返す必要がある場合のアドホックソリューションです。1つの結果タイプと1つの出力パラメーターを設定する代わりに、1つのタプルを返す方がよりエレガントです。この方法では、事前に2番目のパラメーターを宣言する必要はありません。C ++では、その違いがさらに明確になります(結果をconstすることはできますが、out / refパラメーターをconstすることはできません)。
greenoldman 2010年

8
Pythonにはそれがあり、PythonにはC#にないものはありません;)
Evan Plaice

回答:


117

プログラムを作成するとき、クラスの作成を正当化するのに十分な共通性を持たない値のセットを論理的にグループ化することは非常に一般的です。

多くのプログラミング言語では、1つの方法で型を作成しなくても、関係のない値のセットを論理的にグループ化できます。

void M(int foo, string bar, double blah)

論理的には、これは、int、string、doubleの3タプルである引数を1つ取るメソッドMとまったく同じです。しかし、私はあなたが実際に作らないことを望みます:

class MArguments
{
   public int Foo { get; private set; } 
   ... etc

MArgumentsがビジネスロジックで他の意味を持たない限り。

「クラスよりも軽量な構造で、関係のないデータの束をグループ化する」という概念は、メソッドの正式なパラメータリストだけでなく、多くの場所で役立ちます。メソッドが返すものが2つある場合や、1つではなく2つのデータから辞書をキー付けする場合などに便利です。

タプル型をネイティブにサポートするF#のような言語は、ユーザーに大きな柔軟性を提供します。これらは非常に便利なデータ型のセットです。BCLチームは、F#チームと協力してフレームワークの1つのタプルタイプを標準化し、すべての言語がそれらの恩恵を受けることができるようにすることを決定しました。

ただし、現時点では、C#のタプルに対する言語サポートはありません。タプルは、他のフレームワーククラスと同様に、単なる別のデータ型です。それらについて特別なことは何もありません。架空の将来のバージョンのC#でタプルのサポートを追加することを検討しています。タプルに関連するどのような機能が見たいかについて誰かが何か考えを持っている場合、私はそれらを設計チームに伝えたいです。現実的なシナリオは、理論的な考察よりも説得力があります。


1
@MalcomTucker:言語ツールを使用して実際の問題を解決できる豊富な分野として、非同期性と並列性が確実に頭に浮かびます。F#スタイルの非同期ワークフローが必ずしもC#に最適であるとは思いませんが、間違いなく刺激的です。
Eric Lippert、2010年

60
タプルは便利ですが、大きな欠点の1つはわかりやすさです。それが参照するコードを読んで理解するのは難しいItem1Item2の方法でタプルが今までC#言語のサポートを実現しなければ、そのメンバーに名前を付けることができるようにするために素晴らしいだろう...など、(あるいは少なくとも、エイリアス)を使用するコードを可能にしますそれらをより理解しやすくします。そのような仮説の未来では、適切な「形状」のタプルを、個々のパラメーターを受け取るメソッドの正当なパラメーターとして(またその逆も)見たいと思っています。したがって、Tuple<int,string,bool>に渡すことができますM(int,string,bool)。それはメソッドをメモすることをずっと簡単にします。
LBushkin

2
これらの「タプル」は、基本的にすべてのpublicアクセスで、名前のないメンバーを持つ匿名 struct型です。メンバーのセマンティクスについて何も教えてくれないaに対処する必要があるのではなく、プログラマに名前付きメンバーのwithを書いて返してもらいたいのです。structtuple
bobobobo 2013年

1
@ Hi-Angel:議論は、タプルとして数えられるものとそうでないものをめちゃくちゃにすることではなく、現代の基幹業務開発者が生産性を向上させるために使用できる一連の機能についてです。LBushkinは、設計チームが常に聞く機能要求を表現しています。いくつかのフィールドをまとめるだけでクラス全体を作成するという手間と費用なしに、ある種の「レコードタイプ」を作成したいという願望です。C#にはすでにメソッドのこの機能があります。「パラメータリスト」と呼ばれます。
Eric Lippert、2015年

2
@ Hi-Angel:おそらく「メソッドパラメータに名前でアクセスする場合は、別のクラスを作成する必要があります」という引数は作成しないでしょう。メソッドを呼び出すときに、任意の変数のセットを任意の型および名前で瞬時に結び付ける機能。どの言語にもその機能がなかったと想像してください。すべてのメソッドは単一の引数しか取ることができず、2つを渡す場合は、型を作成してそのインスタンスを渡す必要があります。
Eric Lippert

22

タプルはコレクションの不変の実装を提供します

タプルの一般的な使用法は別として:

  • クラスを作成せずに共通の値をグループ化する
  • 関数/メソッドから複数の値を返す
  • 等...

不変オブジェクトは本質的にスレッドセーフです。

不変オブジェクトは、マルチスレッドアプリケーションで役立ちます。複数のスレッドは、他のスレッドによってデータが変更されることを心配することなく、不変オブジェクトによって表されるデータを操作できます。したがって、不変オブジェクトは、可変オブジェクトよりもスレッドセーフであると見なされます。

ウィキペディアの「Immutable Object」から


質問に情報を追加していただきありがとうございます。とても有難い。
Chaddeus

不変コレクションが必要な場合は、タプルではなく不変コレクションを使用する必要があります。違いは、ほとんどの不変コレクションでは、コンパイル時に要素の数を指定する必要がないことです
BlueRaja-Danny Pflughoeft '28

@ BlueRaja-DannyPflughoeft私がこの回答を書いたとき、C#の不変コレクションクラスはBCLで​​まだ利用できませんでした。MSがタプルの実装をC#で無効にしたため、「コレクション」を「オブジェクト」に変更すると思います
Evan Plaice 14

12

refまたはに代わるものを提供しますoutその応答の一部として複数の新しいオブジェクトを返す必要があるメソッドのメソッドがある場合。

また、必要なのが既存の型を2つまたは3つマッシュアップするだけで、この組み合わせのためにクラスや構造体を追加する必要がない場合は、組み込み型を戻り値の型として使用できます。(関数が匿名型を返すことを望んでいますか?これはその状況に対する部分的な回答です。)


くそー。いいね。何年か前にタプルが何であるかを確認したいのですが、
サビランド2013



4

個人的には、調査サイクルにいるとき、または単に「遊ぶ」ときに、タプルは開発の反復的な部分であると私は思います。タプルはジェネリックであるため、ジェネリックパラメーターを使用する場合、特にジェネリックコードを開発したい場合に考える傾向があり、コードの最後から始めます。見て?」

Tupleが形成するコレクションがリストの一部になることはよくあります。List>を見つめると、リストの意図やそのしくみが実際には表現されません。私はしばしばそれと「共存」しますが、リストを操作して値を変更したいと思っていることに気づきます。その時点で、そのための新しいタプルを作成する必要はないので、独自のクラスまたは構造体を作成する必要があります保持するため、操作コードを追加できます。

もちろん、常に拡張メソッドがありますが、その追加コードを一般的な実装に拡張したくない場合がよくあります。

タプルとしてデータを表現したいと思っていて、タプルが利用できない場合がありました。(VS2008)その場合、私は自分のタプルクラスを作成しました-そして、スレッドセーフ(不変)にしません。

したがって、タプルはその目的を説明する型名を失うことを犠牲にして、遅延プログラミングであると私は考えていると思います。その他の費用は、タプルがパラメーターとして使用されている場合は常に、タプルの署名を宣言する必要があることです。いくつかのメソッドが肥大化し始めた後、メソッドのシグネチャをクリーンアップするため、クラスを作成する価値があると私が思うように感じるかもしれません。

私は、あなたがすでに作業しているクラスのパブリックメンバーとしてクラスを持つことから始める傾向があります。しかし、それが単なる値のコレクションを超えた瞬間、それは独自のファイルになり、それを包含クラスの外に移動します。

振り返ってみると、クラスを書きたくなくて、今書いていることを考えたいときにタプルを使用すると思います。つまり、タプルのシグネチャは、このメソッドに必要なデータと、それが返す値を返す方法を理解する間、30分でかなり変化する可能性があります。

コードをリファクタリングする機会があったら、その中のタプルの場所を質問することがよくあります。


3

2010年からの古い質問、そして今では2017年にDotnetが変わり、よりスマートになります。

C#7はタプルの言語サポートを導入し、新しいより効率的なタプルタイプを使用して、タプルのフィールドのセマンティック名を有効にします。

vs 2017と.Net 4.7(またはnugetパッケージSystem.ValueTupleのインストール)では、非常に効率的でシンプルな方法でタプルを作成/使用できます。

     var person = (Id:"123", Name:"john"); //create tuble with two items
     Console.WriteLine($"{person.Id} name:{person.Name}") //access its fields

メソッドから複数の値を返す:

    public (double sum, double average) ComputeSumAndAverage(List<double> list)
    {
       var sum= list.Sum();
        var average = sum/list.Count;
        return (sum, average);
    }

    How to use:

        var list=new List<double>{1,2,3};
        var result = ComputeSumAndAverage(list);
        Console.WriteLine($"Sum={result.sum} Average={result.average}");    

詳細については、https//docs.microsoft.com/en-us/dotnet/csharp/tuplesをご覧ください。


1

タプルは、特定の型を作成したくない場合に、関数から複数の値を返すためによく使用されます。あなたがPythonに精通しているなら、Pythonはこれを長い間持ってきました。


1

関数から複数の値を返します。getCoordinates()は、xまたはyまたはzを返すだけの場合はあまり役に立ちませんが、3つのintを保持する完全なクラスとオブジェクトを作成することもかなり重いようです。


1

一般的な使用法は、2つのフィールドのみを含むクラス/構造体の作成を回避することであり、代わりにタプル(または今のところKeyValuePair)を作成します。戻り値として有用です。Nのパラメーターを渡さないでください...


0

C#でKeyValuePairが更新され、Dictionaryのキーと値のペアを反復処理します。


KeyValuePair特別な目的の回避策と見なすことができます。Pythonでは、dictjustを反復すると(key、value)タプルが返されます。
dan04

はい、pythonのように。:-) c#のKeyValuePairがタプルではないことを知りませんでしたか?
ジュバル

0

関数から値を返すときにとても役立ちます。複数の値を戻すことができますが、これはいくつかのシナリオではかなりの節約になります。


0

タプルとKey-Valueのペアの間でこのパフォーマンスベンチマークに遭遇しましたが、おそらく興味深いでしょう。要約すると、タプルはクラスであるために利点があると言われています。したがって、タプルはスタックではなくヒープに格納され、引数として渡されると、ポインタのみが機能します。ただし、KeyValuePairは構造体であるため、割り当ては高速ですが、使用すると低速になります。

http://www.dotnetperls.com/tuple-keyvaluepair

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.