随着加入的元组在.NET 4类,我一直在努力,以决定是否在我的设计使用起来是一个不错的选择与否。 我看到它的方式,一个元组可以是一个快捷方式编写一个结果类(我相信有其他用途太)。
所以这:
public class ResultType
{
public string StringValue { get; set; }
public int IntValue { get; set; }
}
public ResultType GetAClassedValue()
{
//..Do Some Stuff
ResultType result = new ResultType { StringValue = "A String", IntValue = 2 };
return result;
}
相当于这个:
public Tuple<string, int> GetATupledValue()
{
//...Do Some stuff
Tuple<string, int> result = new Tuple<string, int>("A String", 2);
return result;
}
所以,撇开,我很想念元组点的可能性,是一个例子元组设计不好的选择呢? 对我来说,这似乎是减少混乱,但不能作为自我记录和清洁。 这意味着与该类型ResultType
,这是非常清楚以后什么之类的每一部分意思,但你有额外的代码维护。 随着Tuple<string, int>
你需要查找并弄清每个Item
代表,但你编写和维护更少的代码。
你有过这样的选择的任何经验,将不胜感激。
Answer 1:
如果您可以控制创建和使用它们的元组是伟大的 - 你可以保持上下文,它是理解他们来说至关重要。
在一个公共的API,但是,它们不那么有效。 消费者(不是你)有两种猜测或查找文档,尤其是对于像Tuple<int, int>
我会用他们的私人/内部成员,但使用结果类的公共/ protected成员。
这个答案也有一些信息。
Answer 2:
我看到它的方式,一个元组是一个快捷方式编写一个结果类(我相信有其他用途太)。
确实有其他有价值的用途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一样的技术,其中预测将产生类型,我们通常不会要分配的名称。 (是的,我知道,匿名类型具有相同类型和命名属性是由编译器合并)。
我的经验法则是: 如果你会从你的公共接口返回它-使它成为一个命名的类型 。
用于使用元组我的拇指的其它规则是: 名称方法参数和类型的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...
}
Answer 3:
元组可能是有用的...但他们也可以是一个痛苦之后。 如果你有一个返回的方法Tuple<int,string,string,int>
你是怎么知道这些值是更高版本。 是他们ID, FirstName, LastName, Age
还是他们UnitNumber, Street, City, ZipCode
。
Answer 4:
元组是非常深刻印象的除了从C#程序员的角度CLR。 如果你有一个项目的集合,在长度上变化,你不需要他们有在编译时唯一的静态名称。
但是,如果你有一定长度的集合,这意味着固定的集合中的位置都有一个特定的预先定义的含义。 它始终是更好地给他们适当的静态的名字在这种情况下,而不是记住的重要Item1
, Item2
,等等。
匿名类在C#中已经提供了一个极好的解决方案,以最常见的私人使用的元组,以及他们对项目进行有意义的名字,所以他们实际上是在这个意义上更胜一筹。 唯一的问题是,他们不能泄露出去的命名方法。 我更愿意看到的是限制解除(也许仅适用于私有方法),比对在C#中的元组具体的支持:
private var GetDesserts()
{
return _icecreams.Select(
i => new { icecream = i, topping = new Topping(i) }
);
}
public void Eat()
{
foreach (var dessert in GetDesserts())
{
dessert.icecream.AddTopping(dessert.topping);
dessert.Eat();
}
}
Answer 5:
类似关键字var
,它的目的是作为一个便利-但也容易被滥用。
在我最愚见,不公开Tuple
作为回报类。 使用它私下,如果服务或组件的数据结构需要,但是从公开方法返回形成良好的知名类。
// one possible use of tuple within a private context. would never
// return an opaque non-descript instance as a result, but useful
// when scope is known [ie private] and implementation intimacy is
// expected
public class WorkflowHost
{
// a map of uri's to a workflow service definition
// and workflow service instance. By convention, first
// element of tuple is definition, second element is
// instance
private Dictionary<Uri, Tuple<WorkflowService, WorkflowServiceHost>> _map =
new Dictionary<Uri, Tuple<WorkflowService, WorkflowServiceHost>> ();
}
Answer 6:
使用一类像ResultType
更清晰。 你可以给有意义的名称,以在类中的字段(而用一个元组,他们将被称为Item1
和Item2
)。 如果类型的两个字段是相同的,这更重要的是:名称它们之间明确区分。
Answer 7:
如何在装修排序,去除装饰图案使用元组? (使用Schwartzian变换的Perl的人)。 这里是一个人为的例子,可以肯定的,但元组似乎是处理这种事情的好办法:
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string[] files = Directory.GetFiles("C:\\Windows")
.Select(x => new Tuple<string, string>(x, FirstLine(x)))
.OrderBy(x => x.Item2)
.Select(x => x.Item1).ToArray();
}
static string FirstLine(string path)
{
using (TextReader tr = new StreamReader(
File.Open(path, FileMode.Open)))
{
return tr.ReadLine();
}
}
}
}
现在,我可以使用一个Object []的两个元件或在该特定示例中两种元素的字符串[]。 问题的关键是,我可以用什么作为多数民众赞成在内部使用,是很容易阅读的元组的第二个元素。
Answer 8:
IMO这些“元组”基本上所有的公共访问匿名struct
类型的未命名的成员 。
我会用元组唯一的地方是,当你需要快速团块在一起的一些数据,在非常有限的范围。 数据应的语义是显而易见的 ,因此代码也不是很难看的。 因此,使用一个元组( int
, int
为(行,列))似乎是合理的。 但我很难过,以找到一个优势struct
与名称的成员(所以没有失误是由和行/列并不意外互换)
如果你发送的数据返回给调用者,或者从呼叫者接收数据,你真的应该使用struct
与命名的成员。
举一个简单的例子:
struct Color{ float r,g,b,a ; }
public void setColor( Color color )
{
}
元组版本
public void setColor( Tuple<float,float,float,float> color )
{
// why?
}
我看不到任何优势,在名为成员结构的地方使用元组。 使用无名成员落后为您的代码的可读性和可理解性的一步。
元组让我觉得作为一个偷懒的办法,以避免造成struct
实际命名的成员。 元组,在那里你真的觉得你/或其他人遇到你的代码需要命名成员的过度使用是一件坏事™,如果我见过一个。
Answer 9:
这取决于当然! 正如你所说的,当你想组合到一起供本地消费的一些项目的元组可以节省您的代码和时间。 您也可以使用它们来创建更通用的处理算法,比你可以,如果你通过围绕一个具体的类。 我不记得有多少次,我希望我有一些超越KeyValuePair或DataRow中快速地从一个方法传递一些日期到另一个。
在另一方面,这是很有可能做得太过分,并通过各地的元组,你只能猜测所包含的内容。 如果你要使用跨类元组,也许这将是最好创建一个具体类。
在使用过程中的适度,元组可能导致更简洁和可读的代码。 你可以看一下C ++,STL和提振的元组是如何在其他语言,但最终使用的例子,我们都将不得不尝试着去找到它们如何最适合在.NET环境。
Answer 10:
不要评判我,我不是专家,但现在用在C#中7.x的新的元组,你可以返回类似:
return (string Name1, int Name2)
至少现在,你可以将其命名和开发人员可能会看到一些信息。
Answer 11:
元组是一个无用的框架功能在.NET 4,我认为一个很好的机会与C#4.0偏出。 我会喜欢与一个名为元组的成员,因此,您可以通过名称来代替值1, 值等访问元组的各个领域...
这将需要一个语言(语法)的变化,但它会一直是非常有用的。
Answer 12:
因为没有什么样的值代表表示我个人从来没有使用一个元组作为返回类型。 元组有一些有价值的用途,因为不像对象,他们是值类型,从而理解平等。 正因为如此,我将使用它们作为字典键,如果我需要多按键或者作为的GroupBy子句的关键,如果我想通过多个变量组,不希望嵌套分组(有谁愿意嵌套分组?)。 为了克服极端的冗长的问题,您可以使用一个辅助方法来创建它们。 请记住,如果你经常访问成员(通过项目1,项目2,等等),那么你应该使用不同的结构,如结构或匿名类。
Answer 13:
我用的元组,无论是Tuple
和新的ValueTuple
,在许多不同的场景,并得出以下结论: 不使用 。
每到这时,我遇到了以下问题:
- 码,由于缺乏强有力的命名成为不可读的;
- 无法使用类层次的功能,如基类DTO和子类的DTO等;
- 如果他们在多个地方使用,你最终复制和粘贴,而不是一个干净的类名称这些丑陋的定义。
我的意见是元组是一个损害,而不是一个特征,C#。
我有几分相似,但少了很多苛刻,批评Func<>
和Action<>
这些都是在很多情况下,尤其是简单有效Action
和Func<type>
变种,但任何超出的是,我发现,创建一个委托类型更优雅,可读,可维护,并为您提供更多的功能,如ref
/ out
参数。
文章来源: Is Using .NET 4.0 Tuples in my C# Code a Poor Design Decision?