2009-09-29 65 views
16

我想知道是否有任何允许命名元组的语言。即:具有不同类型和可配置名称的多个变量的对象。允许命名元组的语言

例如为:

public NamedTuple<double:Speed, int:Distance> CalculateStuff(int arg1, int arg2) 

var result = CalculateStuffTuple(1,2); 

Console.WriteLine("Speed is: " + result.Speed.ToString()) 
Console.WriteLine("Distance is: " + result.Distance.ToString()) 

我可以设想一个动态如何支持这样的功能。我经常游泳的静态语言(比如c#)可以做一个Dictionary,但这不是安全的,除非所有的项目都是相同的类型。或者你可以使用Tuple类型,但这意味着你有固定的成员名称(Var1,Var2等)。

你也可以写一个小的自定义类,但这是我想避免的情况。

我可以想象一个宏处理语言可以用静态语言为你编写类似的东西,但我不知道这样的语言。

这是从我的回答this question about return types

+0

我想避免一个自定义的类/结构的原因是,我不喜欢打字!没有什么更多。 – ligos 2009-09-30 03:06:37

+0

这行我应该不包括Tuple。 var result = CalculateStuffTuple(1,2); – 2012-02-03 11:49:38

回答

18

在C#中,您有匿名类型;这些都是相似的,但有其自身的局限性:

var result = new { Speed = 12.4, Distance = 8, Caption = "car 1" }; 

然而,这是很难消费这些作为呼叫者,除非你用“举例投”(脆),反射或dynamic。其中最后一个是最令人开胃的。

dynamic result = GetSomething(); 
Console.WriteLine(result.Speed); 
Console.WriteLine(result.Distance); 

在大多数情况下,使用常规类会更好 - 但这种方法确实有一些实际用途;例如,看看他们如何在ASP中使用。NET MVC简单而方便地传递配置信息(否则需要字典)。有点像jQuery如何让选项作为属性传递给对象。

+0

这似乎是最接近我所要求的(至少在C#中)。 – ligos 2009-09-30 03:03:41

-1

我不确定你会需要什么 - 一个元组只是一个结构,持有不同类型的数据。如果你真的想要命名的属性,你将不得不创建一个自定义类型或动态创建一个匿名类型。

我不知道任何静态类型的语言,可以支持这个,但C#肯定没有。

3

你是说,像Python的collections.namedtuple?那么,Python(当前版本,2.6和3.1)支持他们;-)。但严重的是,我不知道一个静态类型的语言将它们作为内置的语言。

2

在C#中使用结构或类有什么问题?

public class SpeedDistance{ 
    public double Speed; 
    public int Distance; 
} 
+2

那么,公共领域当然是一个坏主意......但是'public double Speed {get; set;}'会做; -p – 2009-09-29 04:30:13

+1

我喜欢我的元组是不可变的。这需要只读变量,而不是一个构造函数,它开始变得太长。 – ligos 2009-09-30 03:05:07

+1

公共领域是可以的,当且仅当所有类都包含。但是元组也可以有很多其他好的属性,这些属性在传递给其他库时会有所帮助。如果它们每次都是从头开始编写的,那么它们就不会互操作。 – 2012-02-03 12:05:07

3

我不知道,如果这是你在寻找什么,但在Haskell,你可以有特定名称和类型的记录:

data Movement = Movement { speed :: Double, distance :: Int } deriving (Show) 

main = do 
    print $ Movement 3.14 100 
    print Movement {distance = 5, speed = 2.1} 
    print Movement {speed = 9, distance = -4} 

输出:

 
Movement {speed = 3.14, distance = 100} 
Movement {speed = 2.1, distance = 5} 
Movement {speed = 9.0, distance = -4} 

但它在技术上不是元组。 Haskell 确实有有元组,但据我所知它们不具名称。

这真的离任何C语言的简单结构都不远。也许我错过了一些问题。

6

埃菲尔允许命名元组。

5

我知道;

  • 的Python(动态,强类型)
  • 艾菲尔(静态,字符串类型)

既可以在.NET

使用

,可能Lisp中,你可以用Lisp的做任何事。

39

老问题,但需要一个更好的解决方案,我认为的。

你可以得到一个名为采取的元组类型的优势,但在一个包装.Item1,.Item2等有意义的属性名称自定义命名类型包裹它的参数。

我太讨厌这样一个事实,即元组具有未命名的参数,使代码无法读取,但不能忽略它自己节省的时间,无法自行实现IComparable,IStructuralEquatable等,以便您可以安全地将结构用作字典关键,例如。

我觉得这是一个非常愉快的妥协:

public class Velocity : Tuple<double, double, string> 
{ 
    public Velocity(double Speed, double Direction, string Units) : base(Speed, Direction, Units) { } 
    public double Speed { get { return this.Item1; } } 
    public double Direction { get { return this.Item2; } } 
    public string Units { get { return this.Item3; } } 
} 

现在不是这种垃圾:

Tuple<double, double, string> myVelocity = new Tuple<double, double, string>(10, 2.34, "cm/s"); 
System.Diagnostics.Debug.Print("Speed: " + myVelocity.Item1); 
System.Diagnostics.Debug.Print("Direction: " + myVelocity.Item2); 
System.Diagnostics.Debug.Print("Units: " + myVelocity.Item3); 

你得到这样做:

Velocity myVelocity2 = new Velocity(10, 2.34, "cm/s"); 
System.Diagnostics.Debug.Print("Speed: " + myVelocity2.Speed); 
System.Diagnostics.Debug.Print("Direction: " + myVelocity2.Direction); 
System.Diagnostics.Debug.Print("Units: " + myVelocity2.Units); 

而且你还受益从所有美妙的元组功能,让你用它作为一个复杂的密钥在字典等

唯一的缺点是,如果你只使用单一方法的范围内,本计划的元组,您必须声明,方法中包含类的范围内的类型。对于大多数应用程序,我不认为这是一个问题。

+0

这其实并不算太坏。除了我必须有一堆围绕'Tuple <>'包装的小类。但它不得不重新实现IEquatable,IComparable等。 – ligos 2012-08-08 23:47:00

+1

我不敢相信我从来没有想到这一点。超级有用。 – 2014-03-24 22:45:37

+0

只是我正在寻找的解决方案。伟大的:) – 2015-03-04 11:02:46

0

谢谢Alain。以下是我如何使用您的提示。对于转盘

<div id="owl" class="owl-carousel owl-theme"> 
    @foreach (var image in Model.Sketches) 
    { 
     <div class="item" > 
      <a href="@image.SketchHref" id="[email protected]" target="_blank" > 
       <img id="[email protected]" class="lazyOwl" style="border:1px solid #d1c7c7;outline : 0;max-height:350px;max-width:400px;" 
        title="click for full size" alt="@image.SketchName" data-src="@image.SketchHref" /></a> 
        <div style="text-align:left;height:auto;vertical-align:bottom;padding:2px;font-size:1em;color:#DF3A01;">Sketch @image.SketchNumber of @Model.Sketches.Count()</div> 
     </div> 
    } 
    </div> 

而对于C#

public List<Sketches> Sketches 
    { 
     get 
     { 
      List<Sketches> hrefs = new List<Sketches>(); 

/* 图像名称

动态图像加载器相匹配的文件夹位置 例如:1234101005_001。GIF就等于 “C:\影像\ 1234 \ 10 \ 1005_BLD \” */

  var sketchFolder = Regex.Replace(some_image, @"(\d{4})(\d{2})(\d{4})", @"c:\Sketches\$1\$2\$3\_BLD"); 
      var sketchHref = Regex.Replace(some_image, @"(\d{4})(\d{2})(\d{4})", @"/sketches/$1/$2/$3/_BLD"); 
      Int16 i = 0; 

      if (System.IO.Directory.Exists(sketchFolder)) 
      { 
       List<string> gifs = GetGifs(sketchFolder); 

       gifs.ForEach(delegate(String gif) 
       { 
        string s = sketchHref + "/" + gif; 
        string f = sketchFolder + "/" + gif; 

        if (System.IO.File.Exists(f)) 
        { 
         Sketches sketch = new Sketches(s, (++i).ToString(), gif); 
         hrefs.Add(sketch); 
        } 
        else // gif does not exist 
        { 
         Sketches sketch = new Sketches("placeholder.png", (++i).ToString(), gif); 
         hrefs.Add(sketch); 
        } 
       }); 
      } 
      else // folder does not exist 
      { 
       Sketches sketch = new Sketches("placeholder.png", (++i).ToString(), ""); 
       hrefs.Add(sketch); 
      } 
      return hrefs; 
     } 
    } 

public class Sketches : Tuple<string, string, string> 
{ 
    public Sketches(string SketchHref, string SketchNumber, string SketchName) : base(SketchHref, SketchNumber, SketchName) { } 
    public string SketchHref { get { return this.Item1; } } 
    public string SketchNumber { get { return this.Item2; } } 
    public string SketchName { get { return this.Item3; } } 
} 
1

斯威夫特允许命名元组。你可以写如下:

let interval = (start: 0, end: 10) 
let start = interval.start 

它们实际上是匿名结构。