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 out
tham 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 var
từ 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...
}