2008-09-30 27 views

Trả lời

73

Tôi đã chỉ cần đọc bài viết này từ MSDN Magazine: Building Tuple

Dưới đây là trích đoạn:

Các 4,0 phát hành sắp tới của Microsoft .NET Framework giới thiệu một loại mới gọi là Hệ thống .Tuple. System.Tuple là một bộ sưu tập có kích thước cố định số không đồng nhất.

Giống như một mảng, một tuple có kích thước cố định mà không thể thay đổi một khi nó đã được tạo ra. Không giống như một mảng, mỗi phần tử trong một bộ túp có thể khác loại và một bộ tuple có thể đảm bảo việc nhập mạnh mẽ cho mỗi phần tử.

Hiện đã là một ví dụ về một tuple nổi xung quanh Framework Microsoft NET, trong namespace System.Collections.Generic: KeyValuePair. Trong khi KeyValuePair có thể được coi như cùng như tuple, vì chúng là cả loại mà giữ hai điều, KeyValuePair cảm thấy khác nhau từ tuple vì nó gợi lên một mối quan hệ giữa hai giá trị nó lưu (và với lý do chính đáng, vì nó hỗ trợ lớp học từ điển ).

Ngoài ra, bộ dữ liệu có thể tùy ý kích thước , trong khi KeyValuePair chỉ giữ hai điều: một khóa và giá trị.


Trong khi một số ngôn ngữ như F # có cú pháp đặc biệt đối với các bộ, bạn có thể sử dụng các loại tuple chung mới từ ngôn ngữ bất kỳ. Xem xét lại ví dụ đầu tiên, chúng ta có thể thấy rằng trong khi hữu ích, các bộ có thể quá rườm rà trong các ngôn ngữ mà không cú pháp cho một tuple:

class Program { 
    static void Main(string[] args) { 
     Tuple<string, int> t = new Tuple<string, int>("Hello", 4); 
     PrintStringAndInt(t.Item1, t.Item2); 
    } 
    static void PrintStringAndInt(string s, int i) { 
     Console.WriteLine("{0} {1}", s, i); 
    } 
} 

Sử dụng từ khóa var từ C# 3.0, chúng ta có thể loại bỏ các chữ ký kiểu trên biến tuple , cho phép mã dễ đọc hơn một chút.

var t = new Tuple<string, int>("Hello", 4); 

Chúng tôi cũng đã thêm một số phương thức nhà máy vào một lớp Tuple tĩnh giúp dễ dàng tạo các bộ dữ liệu bằng ngôn ngữ hỗ trợ suy luận kiểu, như C#.

var t = Tuple.Create("Hello", 4); 
69
#region tuples 

    public class Tuple<T> 
    { 
     public Tuple(T first) 
     { 
      First = first; 
     } 

     public T First { get; set; } 
    } 

    public class Tuple<T, T2> : Tuple<T> 
    { 
     public Tuple(T first, T2 second) 
      : base(first) 
     { 
      Second = second; 
     } 

     public T2 Second { get; set; } 
    } 

    public class Tuple<T, T2, T3> : Tuple<T, T2> 
    { 
     public Tuple(T first, T2 second, T3 third) 
      : base(first, second) 
     { 
      Third = third; 
     } 

     public T3 Third { get; set; } 
    } 

    public class Tuple<T, T2, T3, T4> : Tuple<T, T2, T3> 
    { 
     public Tuple(T first, T2 second, T3 third, T4 fourth) 
      : base(first, second, third) 
     { 
      Fourth = fourth; 
     } 

     public T4 Fourth { get; set; } 
    } 

    #endregion 

Và để làm tờ khai đẹp:

public static class Tuple 
{ 
    //Allows Tuple.New(1, "2") instead of new Tuple<int, string>(1, "2") 
    public static Tuple<T1, T2> New<T1, T2>(T1 t1, T2 t2) 
    { 
     return new Tuple<T1, T2>(t1, t2); 
    } 
    //etc... 
} 
+1

Trong khi câu hỏi là trên MS cung cấp trong .NET 4, đây là cách tốt để quản lý nó ngay bây giờ. +1 –

+6

Cách tiếp cận kế thừa này là tốt nếu bạn không cần phải so sánh hai Tuples cho bình đẳng. Tôi muốn thực hiện IEquatable > và vv trong thực hiện của tôi, vì vậy tôi không thể sử dụng thừa kế, bởi vì tôi không muốn một Tuple bằng với một Tuple . –

+3

@Joel, Bạn có thể có Bằng kiểm tra loại động của cả hai đối số. – RossFabricant

2

Nếu tôi nhớ lớp Khoa học Máy tính của tôi một cách chính xác các bộ chỉ là dữ liệu.

Nếu bạn muốn dữ liệu được nhóm - hãy tạo các lớp có chứa các thuộc tính. Nếu bạn cần một cái gì đó giống như KeyValuePair thì có.

+2

Giống như câu lệnh chỉ là gotos với một khối câu lệnh.Tuples là tốt đẹp nếu bạn có bạn đang sử dụng cho họ và các lớp học dường như không cần thiết và khó sử dụng trong trường hợp cụ thể ... –

0

Tôi rất ngạc nhiên - C# là ngôn ngữ được đánh máy mạnh mẽ, trong khi các bộ tuples phù hợp với nhiều ngôn ngữ được nhập động hơn. C# đã trôi dạt năng động hơn khi thời gian trôi qua, nhưng đó là cú pháp cú pháp, không phải là sự thay đổi thực sự trong các kiểu dữ liệu cơ bản.

Nếu bạn muốn hai giá trị trong một ví dụ, một KeyValuePair <> là một thay thế khá, mặc dù vụng về. Bạn cũng có thể tạo một cấu trúc hoặc một lớp sẽ làm điều tương tự và có thể mở rộng.

+2

"C# đã trôi dạt năng động hơn" - không, nó đã trôi dạt hơn tiềm ẩn/suy ra; nó vẫn là một ngôn ngữ hoàn toàn tĩnh. Tuy nhiên, hỗ trợ năng động tốt hơn (để tiêu thụ các lớp DLR) là khả năng nâng cao ngôn ngữ trong tương lai. –

+2

Làm thế nào để bạn giải thích sự hiện diện của các bộ dữ liệu trong F #, hoặc Haskell, hoặc bất kỳ ngôn ngữ mạnh mẽ và tĩnh nào khác có hỗ trợ đầy đủ cho chúng sau đó ...? –

12

Theo ý kiến ​​của tôi, tính năng loại ẩn danh không phải là một bộ túp, mà là một cấu trúc rất giống nhau. Đầu ra của một số Truy vấn LINQ là các bộ sưu tập các kiểu ẩn danh, hoạt động giống như các bộ dữ liệu.

Đây là một tuyên bố, mà tạo ra một :-) gõ tuple khi đang bay:

var p1 = new {a = "A", b = 3}; 

see: http://www.developer.com/net/csharp/article.php/3589916

3

C# hỗ trợ các bộ đơn giản thông qua Generics khá dễ dàng (theo một câu trả lời trước đó) , và với "gõ mớ" (một trong nhiều cải tiến ngôn ngữ C# có thể) để cải thiện suy luận kiểu chúng có thể rất, rất mạnh mẽ.

Vì nó đáng giá, F # hỗ trợ tuples, và đã chơi với nó, tôi không chắc rằng (ẩn danh) tuples thêm nhiều ... những gì bạn đạt được trong ngắn gọn bạn mất rất nhanh chóng trong mã rõ ràng .

Đối với mã trong một phương thức, có các loại ẩn danh; cho mã đi ra ngoài của một phương pháp, tôi nghĩ rằng tôi sẽ dính vào các loại tên đơn giản. Tất nhiên, nếu một C# trong tương lai làm cho nó dễ dàng hơn để làm cho những bất biến (trong khi vẫn còn dễ dàng để làm việc với) tôi sẽ được hạnh phúc.

+0

Một trong những lợi ích dành cho những thứ như TryParse, nơi bạn có thể viết 'valid value = double.TryParse ("1.02")' và có nhiều giá trị trả lại được gán mà không có bất kỳ tham số vụng về nào. Nhưng nói chung tôi đồng ý rằng cấu trúc dữ liệu hoàn toàn vị trí không phải là một điều tuyệt vời để vượt qua. –

+2

Đồng ý - nhiều giá trị trả lại là trường hợp sử dụng tốt nhất cho các bộ dữ liệu và khác hơn là có rất ít mục đích cho các bộ dữ liệu trong mã. Đó phải là một quy ước chứ không phải là một hạn chế mặc dù các tuple được cho phép. Những gì tôi nghĩ rằng sẽ có được neater là nếu ngôn ngữ NET cung cấp một cách để "disect" trả lại các đối tượng vào nhiều giá trị hơn là giới thiệu các loại dữ liệu tuple. Một cái gì đó như '{j = ErrorCode, h = ResultObj} = SomeFunction()' (nơi 'j' và' h' là người dân địa phương) sẽ hữu ích hơn nhiều so với tuple. –

14

Thực hiện các lớp Tuple hoặc sử dụng lại các lớp F # trong C# chỉ là một nửa câu chuyện - chúng cung cấp cho bạn khả năng tạo tuples tương đối dễ dàng, nhưng không thực sự là đường cú pháp làm cho chúng trở nên dễ sử dụng trong các ngôn ngữ như F #.

Ví dụ trong F # bạn có thể sử dụng mô hình phù hợp để trích xuất tất cả các bộ phận của một tuple trong một Statment let, ví dụ:

let (a, b) = someTupleFunc 

Thật không may làm như vậy bằng cách sử dụng F # lớp từ C# sẽ được ít hơn nhiều thanh lịch:

Tuple<int,int> x = someTupleFunc(); 
int a = x.get_Item1(); 
int b = x.get_Item2(); 

Tuples đại diện cho một phương pháp mạnh mẽ để trả lại nhiều giá trị từ một cuộc gọi hàm mà không cần phải đổ bộ mã hóa hoặc tham số xấu.Tuy nhiên, theo ý kiến ​​của tôi, nếu không có một số cú pháp để tạo ra sự sáng tạo và truy cập của họ thanh lịch hơn, chúng bị hạn chế sử dụng.

+0

Còn về các loại ẩn danh thì sao? –

+0

Điều đó cho phép bạn thay thế Tuple bằng var, nhưng bạn vẫn kết thúc bằng ba dòng mã thay vì một dòng –

+0

Có lẽ đây là điều chúng ta sẽ thấy trong C# 4.0. Đường cú pháp như int a, b = someTupleFunc(); nên hoàn toàn có thể thực hiện được ở cấp trình biên dịch. –

0

Để làm cho các tính năng này hữu ích trong một từ khóa bắt buộc hoặc từ điển, bạn có thể sẽ muốn cung cấp quá tải cho GetHashCode và Equals.

2

Dưới đây là bộ của tôi về các bộ, họ đang autogenerated bởi một kịch bản Python, vì vậy tôi đã có thể đi một chút quá nhiệt tình:

Link to Subversion repository

Bạn sẽ cần một tên người dùng/mật khẩu, họ cả khách

chúng được dựa trên sự kế thừa, nhưng Tuple<Int32,String> sẽ không so sánh tương đương với Tuple<Int32,String,Boolean> ngay cả khi chúng xảy ra để có các giá trị tương tự cho hai thành viên đầu tiên.

Họ cũng triển khai GetHashCode và ToString, v.v. và rất nhiều phương thức trợ giúp nhỏ.

Ví dụ về sử dụng:

Tuple<Int32, String> t1 = new Tuple<Int32, String>(10, "a"); 
Tuple<Int32, String, Boolean> t2 = new Tuple<Int32, String, Boolean>(10, "a", true); 
if (t1.Equals(t2)) 
    Console.Out.WriteLine(t1 + " == " + t2); 
else 
    Console.Out.WriteLine(t1 + " != " + t2); 

Will đầu ra:

10, a != 10, a, True 
+0

Nhưng đó không phải là tất cả. Nếu nó dựa trên thừa kế, tôi giả sử bạn có thể viết 'Tuple t1 = new Tuple (10," a ", true);' v.v. Tôi không chắc chắn liệu có là bất kỳ kịch bản này là mong muốn. – nawfal

15

Có một hợp (không nhanh) C# tuple thực hiện trong Lokad Shared Libraries (nguồn mở, tất nhiên) bao gồm các tính năng bắt buộc sau:

  • 2-5 triển khai tuple bất biến
  • đúng DebuggerDisplayAttribute
  • đúng băm và bình đẳng kiểm tra
  • Helpers để tạo ra các bộ từ các thông số được cung cấp (generics được suy ra bởi trình biên dịch) và phần mở rộng cho các hoạt động dựa trên tập hợp.
  • thử nghiệm sản xuất.
3

Nguồn mở của tôi .NET Sasa library đã có các bộ dữ liệu trong nhiều năm (cùng với nhiều chức năng khác, như phân tích cú pháp MIME đầy đủ). Tôi đã sử dụng nó trong mã sản xuất trong một vài năm nay.

3

C# 7 hỗ trợ các bộ natively:

var unnamedTuple = ("Peter", 29); 
var namedTuple = (Name: "Peter", Age: 29); 
(string Name, double Age) typedTuple = ("Peter", 29); 
+0

Điều này hoạt động ra khỏi hộp là _.NET 4.7_, vì các phiên bản cũ hơn của .NET không chứa các cấu trúc 'ValueTuple' cần thiết. Tuy nhiên, bạn có thể cung cấp những thứ này, ví dụ bằng gói NuGet như [ValueTupleBridge] (https://www.nuget.org/packages/ValueTupleBridge/). – tm1

Các vấn đề liên quan