在我看来,元组是编写结果类的捷径(我相信还有其他用途)。
确实还有其他有价值的用途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 这样的技术,在这种技术中,投影会产生我们通常不想为其分配名称的类型。(是的,我知道编译器会合并具有相同类型和命名属性的匿名类型)。
我的经验法则是: 如果您要从公共接口返回它 - 将其设为命名类型。
我使用元组的另一个经验法则是: 尽可能清楚地命名方法参数和局部变量类型- 使名称代表元组元素之间关系的含义。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...
}