Việc sử dụng .NET 4.0 Tuples trong Mã C # của tôi có phải là một quyết định thiết kế kém không?


166

Với việc bổ sung lớp Tuple trong .net 4, tôi đã cố gắng quyết định xem sử dụng chúng trong thiết kế của tôi có phải là một lựa chọn tồi hay không. Theo cách tôi thấy, một Tuple có thể là một lối tắt để viết một lớp kết quả (tôi chắc chắn cũng có những cách sử dụng khác).

Vậy đây:

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;
}

Tương đương với điều này:

public Tuple<string, int> GetATupledValue()
{
    //...Do Some stuff
    Tuple<string, int> result = new Tuple<string, int>("A String", 2);
    return result;
}

Vì vậy, đặt sang một bên khả năng tôi đang thiếu điểm của Tuples, ví dụ với Tuple có phải là một lựa chọn thiết kế tồi không? Đối với tôi nó có vẻ như ít lộn xộn hơn, nhưng không phải là tài liệu tự làm sạch và sạch sẽ. Có nghĩa là với loại ResultType, sau này rất rõ ràng về ý nghĩa của từng phần của lớp nhưng bạn có thêm mã để duy trì. Với Tuple<string, int>bạn sẽ cần phải tìm kiếm và tìm ra những gì mỗi Itemđại diện, nhưng bạn viết và duy trì ít mã hơn.

Bất kỳ kinh nghiệm bạn có với sự lựa chọn này sẽ được đánh giá rất cao.


16
@Boltbait: bởi vì tuple xuất phát từ lý thuyết tập hợp en.wikipedia.org/wiki/Tuple
Matthew Whited

16
@BoltBait: "tuple" là một tập hợp các giá trị và không nhất thiết phải liên quan đến các hàng trong cơ sở dữ liệu.
Thất vọngWithFormsDesigner

19
Tuples trong c # thậm chí sẽ đẹp hơn nếu có một số hành động giải nén tuple tốt :)
Justin

4
@ John Saunders Câu hỏi của tôi là cụ thể về các quyết định thiết kế trong c #. Tôi không sử dụng bất kỳ ngôn ngữ .net nào khác vì vậy tôi không chắc chắn về cách các bộ dữ liệu tác động đến chúng. Vì vậy, tôi đã đánh dấu nó c #. Nó có vẻ hợp lý với tôi nhưng tôi nghĩ việc thay đổi thành .net cũng ổn.
Jason Webb

13
@ John Saunders: Tôi khá chắc chắn rằng anh ấy đang hỏi về các quyết định thiết kế liên quan đến việc sử dụng hay không sử dụng Tuples trong một ứng dụng được viết hoàn toàn bằng C #. Tôi không tin anh ta đang hỏi về các quyết định thiết kế đã tạo ra ngôn ngữ C #.
Brett Widmeier

Câu trả lời:


163

Tuples rất tuyệt nếu bạn kiểm soát cả việc tạo và sử dụng chúng - bạn có thể duy trì ngữ cảnh, điều cần thiết để hiểu chúng.

Tuy nhiên, trên API công khai, chúng kém hiệu quả hơn. Người tiêu dùng (không phải bạn) phải đoán hoặc tra cứu tài liệu, đặc biệt đối với những thứ nhưTuple<int, int> .

Tôi sẽ sử dụng chúng cho các thành viên riêng tư / nội bộ, nhưng sử dụng các lớp kết quả cho các thành viên công cộng / được bảo vệ.

Câu trả lời này cũng có một số thông tin.


19
Sự khác biệt giữa công / tư là thực sự quan trọng, cảm ơn vì đã đưa nó lên. Trả lại các bộ dữ liệu trong API công khai của bạn là một ý tưởng thực sự tồi tệ, nhưng bên trong nơi mọi thứ có thể được liên kết chặt chẽ (nhưng không sao ) nó vẫn ổn.
Clinton Pierce

36
Kết hợp chặt chẽ, hoặc chặt chẽ tupled? ;)
contactmatt

Tài liệu phù hợp không thể hữu ích ở đây? Ví dụ: Scala's StringOps(về cơ bản là một lớp "phương thức mở rộng" cho Java String) có một phương thức parition(Char => Boolean): (String, String)(lấy vị ngữ, trả về tuple của 2 chuỗi). Rõ ràng đầu ra là gì (rõ ràng một trong số đó sẽ là các ký tự mà vị từ đó là đúng và cái kia là sai, nhưng không rõ đó là ký tự nào). Đó là tài liệu giúp loại bỏ điều này (và khớp mẫu có thể được sử dụng để làm cho nó rõ ràng trong cách sử dụng).
Kat

@Mike: Điều đó khiến bạn khó có thể đúng và dễ sai, dấu hiệu của một API sẽ gây đau khổ cho ai đó ở đâu đó :-)
Bryan Watts

79

Theo cách tôi thấy, một Tuple là một phím tắt để viết một lớp kết quả (tôi chắc chắn cũng có những cách sử dụng khác).

Thực sự có những công dụng quý giá khác cho Tuple<> - hầu hết trong số chúng liên quan đến việc trừu tượng hóa ngữ nghĩa của một nhóm loại cụ thể có chung cấu trúc và coi chúng đơn giản là tập hợp các giá trị. Trong mọi trường hợp, một lợi ích của bộ dữ liệu là chúng tránh làm lộn xộn không gian tên của bạn với các lớp chỉ có dữ liệu để lộ các thuộc tính chứ không phải các phương thức.

Đây là một ví dụ về sử dụng hợp lý cho Tuple<>:

var opponents = new Tuple<Player,Player>( playerBob, playerSam );

Trong ví dụ trên, chúng tôi muốn đại diện cho một cặp đối thủ, tuple là một cách thuận tiện để ghép các trường hợp này mà không phải tạo một lớp mới. Đây là một ví dụ khác:

var pokerHand = Tuple.Create( card1, card2, card3, card4, card5 );

Một ván bài xì phé có thể được coi là chỉ một bộ bài - và tuple (có thể) là một cách hợp lý để thể hiện khái niệm đó.

bỏ qua khả năng tôi đang thiếu quan điểm của Tuples, ví dụ với Tuple có phải là một lựa chọn thiết kế tồi không?

Trả lại các Tuple<>thể hiện được gõ mạnh như một phần của API công khai cho loại công khai hiếm khi là một ý tưởng hay. Như chính bạn nhận ra, bộ dữ liệu yêu cầu các bên liên quan (tác giả thư viện, người sử dụng thư viện) phải đồng ý trước về mục đích và giải thích các loại bộ dữ liệu đang được sử dụng. Nó đủ thách thức để tạo các API trực quan và rõ ràng, sử dụng Tuple<>công khai chỉ che khuất ý định và hành vi của API.

Các loại ẩn danh cũng là một loại tuple - tuy nhiên, chúng được gõ mạnh và cho phép bạn chỉ định tên rõ ràng, nhiều thông tin cho các thuộc tính thuộc về loại. Nhưng các loại ẩn danh rất khó sử dụng trên các phương pháp khác nhau - chúng chủ yếu được thêm vào các công nghệ hỗ trợ như LINQ nơi các phép chiếu sẽ tạo ra các loại mà chúng ta thường không muốn gán tên. (Có, tôi biết rằng các loại ẩn danh có cùng loại và thuộc tính được đặt tên được hợp nhất bởi trình biên dịch).

Nguyên tắc nhỏ của tôi là: nếu bạn sẽ trả nó từ giao diện công cộng của bạn - hãy biến nó thành một loại được đặt tên .

Quy tắc ngón tay cái khác của tôi khi sử dụng bộ dữ liệu là: đối số phương thức tên và biến cục bộ của loại Tuple<>càng rõ ràng càng tốt - làm cho tên thể hiện ý nghĩa của các mối quan hệ giữa các yếu tố của bộ dữ liệu. Hãy nghĩ về var opponents = ...ví dụ của tôi .

Đây là một ví dụ về trường hợp trong thế giới thực mà tôi đã sử dụng Tuple<>để tránh khai báo loại chỉ có dữ liệu để chỉ sử dụng trong hội đồng của riêng tôi . Tình huống liên quan đến thực tế là khi sử dụng từ điển chung có chứa các loại ẩn danh, việc sử dụng TryGetValue()phương thức để tìm các mục trong từ điển trở nên khó khăn vì phương thức này yêu cầu một outtham số không thể đặt tên:

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 Có một cách khác (đơn giản hơn) để khắc phục các vấn đề phát sinh từ các loại ẩn danh trong từ điển và đó là sử dụng vartừ khóa để trình biên dịch 'suy ra' loại cho bạn. Đây là phiên bản:

var foundItem = peopleDict.FirstOrDefault().Value;
if( peopleDict.TryGetValue( "Smith", out foundItem ) )
{
   // use foundItem...
}

5
@stakx: Vâng, tôi đồng ý. Nhưng hãy ghi nhớ - ví dụ chủ yếu nhằm minh họa các trường hợp khi việc sử dụng Tuple<> có thể có ý nghĩa. Luôn có những lựa chọn thay thế ...
LBushkin

1
Tôi nghĩ rằng việc thay thế các tham số bằng Tuple, như trong TryGetValue hoặc TryPude, là một trong số ít trường hợp có thể có API công khai trả về Tuple. Trong thực tế, ít nhất một ngôn ngữ .NET tự động làm cho API này thay đổi cho bạn.
Joel Mueller

1
@stakx: Tuples cũng bất biến, trong khi mảng thì không.
Robert Paulson

2
Tôi hiểu rằng Tuples chỉ hữu ích như các đối tượng người chơi poker bất biến.
Gennady Vanin Геннадий Внаин

2
+1 Câu trả lời tuyệt vời - Tôi yêu hai ví dụ ban đầu của bạn thực sự đã thay đổi suy nghĩ của tôi một chút. Tôi chưa bao giờ thấy các ví dụ trước đây khi một tuple ít nhất phù hợp như một cấu trúc hoặc kiểu tùy chỉnh. Tuy nhiên, "ví dụ thực tế" cuối cùng của bạn đối với tôi dường như không thêm nhiều giá trị nữa. Hai ví dụ đầu tiên là hoàn hảo và đơn giản. Điều cuối cùng là một chút khó hiểu và loại "PS" của bạn làm cho nó vô dụng vì cách tiếp cận thay thế của bạn đơn giản hơn nhiều và không yêu cầu bộ dữ liệu.
chiccodoro

18

Tuples có thể hữu ích ... nhưng chúng cũng có thể là một nỗi đau sau này. Nếu bạn có một phương thức trả về, Tuple<int,string,string,int>làm thế nào để bạn biết những giá trị đó là gì sau này. Là họ ID, FirstName, LastName, Agehay là họ UnitNumber, Street, City, ZipCode.


9

Tuples là sự bổ sung khá ấn tượng cho CLR từ góc độ của một lập trình viên C #. Nếu bạn có một bộ sưu tập các vật phẩm có độ dài khác nhau, bạn không cần chúng có các tên tĩnh duy nhất tại thời điểm biên dịch.

Nhưng nếu bạn có một bộ sưu tập có độ dài không đổi, thì điều này ngụ ý rằng các vị trí cố định trong bộ sưu tập đều có một ý nghĩa được xác định trước cụ thể. Và đó là lúc nào cũng tốt hơn để cung cấp cho họ tên tĩnh thích hợp trong trường hợp đó, thay vì phải nhớ ý nghĩa của Item1, Item2vv

Các lớp ẩn danh trong C # đã cung cấp một giải pháp tuyệt vời cho việc sử dụng bộ dữ liệu cá nhân phổ biến nhất và họ đặt tên có ý nghĩa cho các mục, vì vậy chúng thực sự vượt trội theo nghĩa đó. Vấn đề duy nhất là chúng không thể rò rỉ ra khỏi các phương thức được đặt tên. Tôi muốn thấy hạn chế đó được gỡ bỏ (có lẽ chỉ dành cho các phương thức riêng tư) hơn là có hỗ trợ cụ thể cho các bộ dữ liệu trong 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();
    }
}

Là một tính năng chung, những gì tôi muốn thấy sẽ là .net để xác định một tiêu chuẩn cho một vài loại ẩn danh đặc biệt, ví dụ như struct var SimpleStruct {int x, int y;}sẽ xác định một cấu trúc có tên bắt đầu bằng một hướng dẫn liên quan đến các cấu trúc đơn giản và có cái gì đó như được {System.Int16 x}{System.Int16 y}nối thêm; bất kỳ tên nào bắt đầu bằng GUID đó sẽ được yêu cầu để thể hiện một cấu trúc chỉ chứa các phần tử và nội dung được chỉ định cụ thể đó; nếu nhiều định nghĩa cho cùng một tên nằm trong phạm vi và chúng khớp nhau, tất cả sẽ được coi là cùng loại.
supercat

Một điều như vậy sẽ hữu ích cho một vài loại, bao gồm các lớp và cấu trúc có thể thay đổi và bất biến cũng như các giao diện và đại biểu để sử dụng trong các tình huống trong đó cấu trúc khớp phải được coi là phù hợp với ngữ nghĩa. Mặc dù có nhiều lý do tại sao có thể hữu ích khi có hai loại đại biểu có cùng tham số không được xem là có thể hoán đổi cho nhau, nhưng cũng có thể hữu ích nếu người ta có thể chỉ định rằng một phương thức muốn một đại biểu có một số kết hợp tham số nhưng vượt quá điều đó Không quan tâm đó là loại đại biểu nào.
supercat

Thật không may là nếu hai người khác nhau muốn viết các hàm lấy các đại biểu đầu vào cần một reftham số duy nhất , cách duy nhất có thể có một đại biểu có thể được truyền cho cả hai chức năng là nếu một người tạo và biên dịch một đại biểu loại và đưa nó cho người khác để xây dựng chống lại. Không có cách nào cả hai người có thể chỉ ra rằng hai loại nên được coi là đồng nghĩa.
supercat

Bạn có bất kỳ ví dụ cụ thể nào về nơi bạn sử dụng các lớp ẩn danh hơn là Tuplekhông? Tôi chỉ lướt qua 50 vị trí trong cơ sở mã của mình, nơi tôi đang sử dụng bộ dữ liệu và tất cả đều là giá trị trả về (thông thường yield return) hoặc là các phần tử của các bộ sưu tập được sử dụng ở nơi khác, vì vậy không đi đến các lớp ẩn danh.

2
@Jonof ALLTrades - ý kiến ​​có thể khác nhau về điều đó, nhưng tôi cố gắng thiết kế các phương thức công khai như thể chúng sẽ được sử dụng bởi người khác, ngay cả khi ai đó là tôi, vì vậy tôi đang cung cấp cho mình dịch vụ khách hàng tốt! Bạn có xu hướng gọi một chức năng nhiều lần hơn bạn viết nó. :)
Daniel Earwicker

8

Tương tự như từ khóa var, nó được dùng như một sự tiện lợi - nhưng lại dễ bị lạm dụng.

Theo ý kiến ​​khiêm tốn nhất của tôi, đừng phơi bày Tuplenhư một lớp trở về. Sử dụng nó một cách riêng tư, nếu cấu trúc dữ liệu của một dịch vụ hoặc thành phần yêu cầu nó, nhưng trả về các lớp nổi tiếng được hình thành rõ ràng từ các phương thức công khai.

// 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>> ();
}

2
Các ngôn ngữ "RAD" chính (Java là ví dụ tốt nhất) luôn chọn sự an toàn và tránh tự bắn mình trong các tình huống kiểu chân. Tôi rất vui vì Microsoft đang nắm lấy một số cơ hội với C # và mang lại cho ngôn ngữ một sức mạnh tốt đẹp, ngay cả khi nó có thể bị lạm dụng.
Matt Greer

4
Từ khóa var không thể lạm dụng. Có lẽ bạn có nghĩa là năng động?
Chris Marisic

@Chris Marisic, chỉ cần làm rõ tôi không có ý trong cùng một kịch bản - bạn hoàn toàn chính xác, varkhông thể bị trả lại hoặc tồn tại bên ngoài phạm vi được tuyên bố của nó. tuy nhiên, vẫn có thể sử dụng nó vượt quá mục đích đã định và bị "lạm dụng"
johnny g

5
Tôi vẫn đứng trên var đó không thể bị lạm dụng thời gian. Nó chỉ đơn thuần là một từ khóa để thực hiện một định nghĩa biến ngắn hơn. Đối số của bạn có lẽ là về các loại ẩn danh nhưng ngay cả những loại thực sự không thể bị lạm dụng vì chúng vẫn là các loại được liên kết tĩnh bình thường hiện nay là một câu chuyện hoàn toàn khác.
Chris Marisic

4
var có thể bị lạm dụng theo nghĩa là nếu nó bị lạm dụng quá mức, đôi khi nó có thể gây ra vấn đề cho người đọc mã. Đặc biệt là nếu bạn không ở trong Visual Studio và thiếu thông tin.
Matt Greer

5

Sử dụng một lớp như thế ResultTypelà rõ ràng hơn. Bạn có thể đặt tên có ý nghĩa cho các trường trong lớp (trong khi với một tuple chúng sẽ được gọi Item1Item2). Điều này thậm chí còn quan trọng hơn nếu các loại của hai trường giống nhau: tên phân biệt rõ ràng giữa chúng.


Một lợi thế nhỏ nữa: bạn có thể sắp xếp lại các tham số cho một lớp một cách an toàn. Làm như vậy cho một tuple sẽ phá vỡ mã và nếu các trường có các loại tương tự, điều này có thể không thể phát hiện được tại thời điểm biên dịch.

Tôi đồng ý, Tuples được sử dụng khi nhà phát triển thiếu năng lượng để nghĩ về một tên lớp có ý nghĩa nhóm các tên thuộc tính có ý nghĩa. Lập trình là về giao tiếp. Tuples là một antipotype để giao tiếp. Tôi đã ưu tiên Microsoft bỏ nó ra khỏi ngôn ngữ để buộc các nhà phát triển đưa ra quyết định thiết kế tốt.
mike gold

5

Làm thế nào về việc sử dụng Tuples trong một mô hình trang trí sắp xếp-trang trí? (Biến đổi Schwartzian cho người Perl). Đây là một ví dụ giả định, để chắc chắn, nhưng Tuples dường như là một cách tốt để xử lý loại điều này:

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();
            }
        }
    }
}

Bây giờ, tôi có thể đã sử dụng một Object [] gồm hai phần tử hoặc trong ví dụ cụ thể này, một chuỗi [] gồm hai phần tử. Vấn đề là tôi có thể sử dụng bất cứ thứ gì làm yếu tố thứ hai trong Tuple được sử dụng nội bộ và khá dễ đọc.


3
Bạn có thể sử dụng Tuple.Create thay cho constructor. Nó ngắn hơn.
Kugel

một loại ẩn danh sẽ dễ đọc hơn nhiều; như sử dụng tên biến thực thay vì 'x'
Dave Cousineau

Nó sẽ bây giờ . Đó là một vấn đề SO, câu trả lời được đăng từ nhiều năm trước không bao giờ được làm sạch hoặc cập nhật cho công nghệ mới.
Clinton Pierce

4

IMO các "bộ dữ liệu" này về cơ bản là tất cả các structloại ẩn danh truy cập công khai với các thành viên chưa được đặt tên .

Nơi duy nhất tôi sẽ sử dụng tuple là khi bạn cần nhanh chóng kết hợp một số dữ liệu, trong một phạm vi rất hạn chế. Các ngữ nghĩa của dữ liệu nên rõ ràng , vì vậy mã không khó đọc. Vì vậy, sử dụng một tuple ( int, int) cho (hàng, col) có vẻ hợp lý. Nhưng tôi rất khó tìm được lợi thế so structvới các thành viên được nêu tên (vì vậy không có lỗi nào được thực hiện và hàng / cột không vô tình thay thế cho nhau)

Nếu bạn đang gửi dữ liệu trở lại cho người gọi hoặc chấp nhận dữ liệu từ người gọi, bạn thực sự nên sử dụng một structvới các thành viên được đặt tên.

Lấy một ví dụ đơn giản:

struct Color{ float r,g,b,a ; }
public void setColor( Color color )
{
}

Phiên bản tuple

public void setColor( Tuple<float,float,float,float> color )
{
  // why?
}

Tôi không thấy bất kỳ lợi thế nào khi sử dụng tuple ở vị trí của một cấu trúc với các thành viên được đặt tên. Sử dụng các thành viên không tên là một bước lùi cho tính dễ đọc và dễ hiểu của mã của bạn.

Tuple tấn công tôi như một cách lười biếng để tránh tạo ra một structthành viên có tên thực tế. Việc sử dụng quá mức tuple, nơi bạn thực sự cảm thấy bạn / hoặc người khác gặp mã của bạn sẽ cần các thành viên có tên là A Bad Thing ™ nếu tôi từng thấy.


3

Đừng phán xét tôi, tôi không phải là chuyên gia, nhưng với Tuples mới trong C # 7.x bây giờ, bạn có thể trả về một cái gì đó như:

return (string Name1, int Name2)

Ít nhất bây giờ bạn có thể đặt tên cho nó và các nhà phát triển có thể thấy một số thông tin.


2

Nó phụ thuộc, tất nhiên! Như bạn đã nói, một tuple có thể giúp bạn tiết kiệm mã và thời gian khi bạn muốn nhóm một số mặt hàng lại với nhau để tiêu thụ tại địa phương. Bạn cũng có thể sử dụng chúng để tạo ra các thuật toán xử lý chung hơn bạn có thể nếu bạn vượt qua một lớp cụ thể xung quanh. Tôi không thể nhớ bao nhiêu lần tôi ước mình có thứ gì đó ngoài KeyValuePair hoặc DataRow để nhanh chóng chuyển một ngày nào đó từ phương thức này sang phương pháp khác.

Mặt khác, hoàn toàn có thể lạm dụng nó và vượt qua các bộ dữ liệu mà bạn chỉ có thể đoán những gì chúng chứa. Nếu bạn định sử dụng một tuple trên các lớp, có lẽ sẽ tốt hơn nếu tạo một lớp cụ thể.

Được sử dụng trong chừng mực, các bộ dữ liệu có thể dẫn đến mã ngắn gọn và dễ đọc hơn. Bạn có thể tìm đến C ++, STL và Boost để biết ví dụ về cách sử dụng Tuples trong các ngôn ngữ khác, nhưng cuối cùng, tất cả chúng ta sẽ phải thử nghiệm để tìm ra cách chúng phù hợp nhất trong môi trường .NET.


1

Tuples là một tính năng khung vô dụng trong .NET 4. Tôi nghĩ rằng một cơ hội tuyệt vời đã bị bỏ lỡ với C # 4.0. Tôi rất thích có các bộ dữ liệu với các thành viên được đặt tên, vì vậy bạn có thể truy cập vào các trường khác nhau của một bộ theo tên thay vì Value1 , Value2 , v.v ...

Nó sẽ yêu cầu thay đổi ngôn ngữ (cú pháp), nhưng nó sẽ rất hữu ích.


Làm thế nào là tuples một "tính năng ngôn ngữ"? Đó là một lớp có sẵn cho tất cả các ngôn ngữ .net phải không?
Jason Webb

11
Tương đối vô dụng với C #, có lẽ. Nhưng System.Tuple không được thêm vào khung vì C #. Nó đã được thêm vào để dễ dàng tương tác giữa F # và các ngôn ngữ khác.
Joel Mueller

@Jason: Tôi không nói đó là một tính năng ngôn ngữ (tôi đã gõ nhầm, nhưng tôi đã sửa nó trước khi bạn đưa ra nhận xét này).
Philippe Leybaert

2
@Jason - các ngôn ngữ có hỗ trợ trực tiếp cho các bộ dữ liệu có hỗ trợ ngầm cho việc giải mã các bộ dữ liệu thành các giá trị thành phần của chúng. Mã được viết bằng các ngôn ngữ đó thường không bao giờ, truy cập vào các thuộc tính Item1, Item2. let success, value = MethodThatReturnsATuple()
Joel Mueller

@Joel: câu hỏi này được gắn thẻ là C #, vì vậy bằng cách nào đó về C #. Tôi vẫn nghĩ rằng họ có thể đã biến nó thành một tính năng hạng nhất trong ngôn ngữ.
Philippe Leybaert

1

Cá nhân tôi sẽ không bao giờ sử dụng Tuple làm kiểu trả về vì không có dấu hiệu nào cho thấy giá trị đại diện cho cái gì. Tuples có một số cách sử dụng có giá trị vì không giống như các đối tượng, chúng là các loại giá trị và do đó hiểu được sự bình đẳng. Do đó, tôi sẽ sử dụng chúng làm khóa từ điển nếu tôi cần khóa nhiều phần hoặc làm khóa cho mệnh đề GroupBy nếu tôi muốn nhóm theo nhiều biến và không muốn nhóm lồng nhau (Ai đã từng muốn nhóm lồng nhau?). Để khắc phục vấn đề với mức độ dài dòng, bạn có thể tạo chúng bằng phương pháp trợ giúp. Hãy ghi nhớ nếu bạn thường xuyên truy cập các thành viên (thông qua Item1, Item2, v.v.) thì có lẽ bạn nên sử dụng một cấu trúc khác như cấu trúc hoặc một lớp ẩn danh.


0

Tôi đã sử dụng các bộ dữ liệu, cả Tuplemới và mới ValueTuple, trong một số tình huống khác nhau và đi đến kết luận sau: không sử dụng .

Mỗi lần, tôi gặp phải các vấn đề sau:

  • mã trở nên không thể đọc được do thiếu đặt tên mạnh;
  • không thể sử dụng các tính năng phân cấp lớp, chẳng hạn như DTO lớp cơ sở và DTO lớp con, v.v.;
  • nếu chúng được sử dụng ở nhiều nơi, cuối cùng bạn sẽ sao chép và dán các định nghĩa xấu này, thay vì tên lớp sạch.

Ý kiến ​​của tôi là tuples là một bất lợi, không phải là một tính năng, của C #.

Tôi có phần nào tương tự, nhưng ít gay gắt hơn, chỉ trích Func<>Action<>. Chúng rất hữu ích trong nhiều tình huống, đặc biệt là các biến thể đơn giản ActionFunc<type>biến thể, nhưng bất cứ điều gì khác, tôi thấy rằng việc tạo một kiểu đại biểu là thanh lịch hơn, dễ đọc hơn, có thể duy trì và cung cấp cho bạn nhiều tính năng hơn, như ref/ outtham số.


Tôi đã đề cập đến các bộ dữ liệu có tên ValueTuple- và tôi cũng không thích chúng. Đầu tiên, việc đặt tên không mạnh, đó là một gợi ý, rất dễ gây rối bởi vì nó có thể được gán ngầm cho một Tuplehoặc ValueTuplecùng số lượng và loại mặt hàng. Thứ hai, việc thiếu sự kế thừa và nhu cầu sao chép dán toàn bộ định nghĩa từ nơi này sang nơi khác vẫn còn bất lợi.
Ông TA

Tôi đồng ý với những điểm đó. Tôi cố gắng chỉ sử dụng Tuples khi tôi kiểm soát nhà sản xuất và người tiêu dùng và nếu chúng không quá "xa". Ý nghĩa, nhà sản xuất và người tiêu dùng trong cùng một phương thức = 'đóng', trong khi nhà sản xuất và người tiêu dùng ở các tổ hợp khác nhau = 'năm ánh sáng'. Vì vậy, nếu tôi tạo các bộ dữ liệu khi bắt đầu một phương thức và sử dụng chúng ở cuối? Chắc chắn, tôi ổn với điều đó. Tôi cũng tài liệu các điều khoản và như vậy. Nhưng vâng, tôi đồng ý rằng nhìn chung chúng không phải là lựa chọn đúng đắn.
Mike Christiansen
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.