私の見方では、タプルは結果クラスを作成するためのショートカットです(他の用途もあると確信しています)。
実際、他にも価値のある用途がありTuple<>
ます。それらのほとんどは、類似した構造を共有する特定のタイプのグループのセマンティクスを抽象化し、それらを単純に順序付けられた値のセットとして扱うことを含みます。すべての場合において、タプルの利点は、プロパティを公開するがメソッドは公開しないデータのみのクラスで名前空間が乱雑になるのを回避できることです。
の合理的な使用例を次に示しますTuple<>
。
var opponents = new Tuple<Player,Player>( playerBob, playerSam );
上記の例では、対戦相手のペアを表現したいので、タプルは、新しいクラスを作成せずにこれらのインスタンスをペアにする便利な方法です。別の例を次に示します。
var pokerHand = Tuple.Create( card1, card2, card3, card4, card5 );
ポーカーハンドは単なるカードのセットと考えることができ、タプル(おそらく)はその概念を表現するための合理的な方法です。
タプルのポイントを見逃している可能性は別として、タプルを使用した例は悪い設計上の選択ですか?
Tuple<>
パブリックタイプのパブリックAPIの一部として強く型付けされたインスタンスを返すことは、めったに良い考えではありません。ご存知のように、タプルでは、関係者(ライブラリの作成者、ライブラリのユーザー)が、使用されているタプルの種類の目的と解釈について事前に合意する必要があります。直感的で明確なAPIを作成することは十分に困難であり、Tuple<>
公に使用するとAPIの意図と動作が曖昧になるだけです。
匿名型も一種のタプルですが、強く型付けされており、型に属するプロパティに明確で有益な名前を指定できます。ただし、匿名型はさまざまな方法で使用するのが困難です。これらは主に、通常は名前を割り当てたくない型をプロジェクションが生成するLINQなどのテクノロジをサポートするために追加されました。(はい、同じ型と名前付きプロパティを持つ匿名型がコンパイラーによって統合されることを私は知っています)。
私の経験則は次のとおり です。パブリックインターフェイスから返す場合は、名前付きタイプにします。
タプルを使用するためのもう1つの経験則は、 メソッド引数とタイプのlocalc変数にTuple<>
できるだけ明確に名前を付けることです。名前がタプルの要素間の関係の意味を表すようにします。var opponents = ...
私の例を考えてみてください。
これは、自分のアセンブリ内でのみ使用Tuple<>
するデータのみの型を宣言することを回避するために使用した実際のケースの例です。この状況では、匿名型を含むジェネリックディクショナリを使用すると、メソッドに名前を付けることができないパラメータが必要になるため、メソッドを使用してディクショナリ内のアイテムを検索することが困難になるという事実が関係しています。TryGetValue()
out
public static class DictionaryExt
{
// helper method that allows compiler to provide type inference
// when attempting to locate optionally existent items in a dictionary
public static Tuple<TValue,bool> Find<TKey,TValue>(
this IDictionary<TKey,TValue> dict, TKey keyToFind )
{
TValue foundValue = default(TValue);
bool wasFound = dict.TryGetValue( keyToFind, out foundValue );
return Tuple.Create( foundValue, wasFound );
}
}
public class Program
{
public static void Main()
{
var people = new[] { new { LastName = "Smith", FirstName = "Joe" },
new { LastName = "Sanders", FirstName = "Bob" } };
var peopleDict = people.ToDictionary( d => d.LastName );
// ??? foundItem <= what type would you put here?
// peopleDict.TryGetValue( "Smith", out ??? );
// so instead, we use our Find() extension:
var result = peopleDict.Find( "Smith" );
if( result.First )
{
Console.WriteLine( result.Second );
}
}
}
PS辞書の匿名型から生じる問題を回避する別の(より簡単な)方法があります。それは、var
キーワードを使用して、コンパイラーに型を「推測」させることです。そのバージョンは次のとおりです。
var foundItem = peopleDict.FirstOrDefault().Value;
if( peopleDict.TryGetValue( "Smith", out foundItem ) )
{
// use foundItem...
}