Jas*_*ebb 166 .net c# tuples application-design
随着.net 4 中的Tuple类的增加,我一直试图决定在我的设计中使用它们是否是一个糟糕的选择.我看到它的方式,一个元组可以是编写结果类的快捷方式(我相信还有其他用途).
所以这:
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;
}
Run Code Online (Sandbox Code Playgroud)
相当于:
public Tuple<string, int> GetATupledValue()
{
//...Do Some stuff
Tuple<string, int> result = new Tuple<string, int>("A String", 2);
return result;
}
Run Code Online (Sandbox Code Playgroud)
因此,抛开我错过了元组点的可能性,是一个Tuple设计选择不好的例子吗?对我来说,它似乎不那么混乱,但不像自我记录和干净.这意味着对于类型ResultType
,后面很清楚类的每个部分意味着什么,但你有额外的代码来维护.随着Tuple<string, int>
您将需要查找并弄清每一个Item
代表,但你编写和维护更少的代码.
您对此选择的任何经验将不胜感激.
LBu*_*kin 79
我看到它的方式,一个元组是编写结果类的快捷方式(我相信还有其他用途).
确实存在其他有价值的用途Tuple<>
- 其中大多数涉及抽象出具有相似结构的特定类型组的语义,并将它们简单地视为有序的值集.在所有情况下,元组的一个好处是它们可以避免使用公开属性但不公开方法的仅数据类来混淆命名空间.
以下是合理使用的示例Tuple<>
:
var opponents = new Tuple<Player,Player>( playerBob, playerSam );
Run Code Online (Sandbox Code Playgroud)
在上面的例子中,我们想要代表一对对手,元组是一种方便的方式来配对这些实例而无需创建新类.这是另一个例子:
var pokerHand = Tuple.Create( card1, card2, card3, card4, card5 );
Run Code Online (Sandbox Code Playgroud)
扑克牌可以被认为只是一组牌 - 而元组(可能是)表达这个概念的合理方式.
撇开我错过了元组点的可能性,是一个Tuple设计选择不好的例子吗?
将强类型Tuple<>
实例作为公共类型的公共API的一部分返回很少是个好主意.正如您自己认识到的那样,元组要求所涉及的各方(图书馆作者,图书馆用户)提前就目前使用的元组类型和解释达成一致.创建直观且清晰的API是非常具有挑战性的,Tuple<>
仅使用公开的API会模糊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 );
}
}
}
Run Code Online (Sandbox Code Playgroud)
PS还有另一种(更简单的)方法来解决字典中匿名类型引起的问题,那就是使用var
关键字让编译器"推断"你的类型.这是那个版本:
var foundItem = peopleDict.FirstOrDefault().Value;
if( peopleDict.TryGetValue( "Smith", out foundItem ) )
{
// use foundItem...
}
Run Code Online (Sandbox Code Playgroud)
Mat*_*ted 18
元组可能很有用......但它们之后也会很痛苦.如果你有一个返回方法,Tuple<int,string,string,int>
你怎么知道这些值后来是什么.是他们ID, FirstName, LastName, Age
还是他们UnitNumber, Street, City, ZipCode
.
从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();
}
}
Run Code Online (Sandbox Code Playgroud)
与关键字类似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>> ();
}
Run Code Online (Sandbox Code Playgroud)
使用类ResultType
更清晰.你可以给有意义的名称,以在类中的字段(而用一个元组,他们将被称为Item1
和Item2
).如果两个字段的类型相同,则更为重要:名称清楚地区分它们.
如何在装饰 - 排序 - 未装饰模式中使用元组?(Schwartzian变换为Perl人).这是一个人为的例子,但是Tuples似乎是处理这类事情的好方法:
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();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在,我可以使用两个元素的Object [],或者在这个特定示例中使用两个元素的字符串[].关键是我可以使用任何东西作为内部使用的元组中的第二个元素,并且非常容易阅读.
归档时间: |
|
查看次数: |
38346 次 |
最近记录: |