2010-07-12 27 views
6

Vì vậy, tôi phải thiết kế một lớp hoạt động trên một tập hợp các đối tượng được ghép nối. Có một ánh xạ một-một giữa các đối tượng. Tôi mong rằng khách hàng của lớp đã thiết lập bản đồ này trước khi sử dụng lớp của tôi.Cách trực quan nhất để yêu cầu đối tượng theo cặp là gì?

Câu hỏi của tôi là cách tốt nhất để cho phép người dùng lớp học của tôi cung cấp cho tôi thông tin đó là gì?

Có phải yêu cầu một bộ sưu tập các cặp như thế này không?

MyClass(IEnumerable<KeyValuePair<Object, Object>> objects) 

Hoặc các bộ sưu tập riêng biệt như thế này?

MyClass(IEnumberable<Object> x, IEnumerable<Object> y) 

Hoặc có tùy chọn khác không?

Tôi thích người đầu tiên vì mối quan hệ rõ ràng, tôi không thích nó vì công việc bổ sung mà nó đặt lên máy khách.

Tôi thích thứ hai vì các loại nguyên thủy hơn và yêu cầu ít công việc hơn, tôi không thích nó vì ánh xạ không rõ ràng. Tôi phải thừa nhận thứ tự là chính xác.

Ý kiến ​​xin vui lòng?

+0

Tôi thích là người đầu tiên với cùng lý do, mối quan hệ là rõ ràng. Vì KeyValuePair là phổ biến trong toàn bộ khuôn khổ, tôi không thấy có bất kỳ "công việc bổ sung" nào Một nhược điểm có thể có là KeyValuePair infers rằng T2 bằng cách nào đó được khóa bởi T1, nếu mối quan hệ giữa chúng là nhiều hơn, bạn có thể cuộn loại của riêng bạn (ví dụ: Pair ). – Tergiver

Trả lời

10

Trong .NET 4 bạn nên sử dụng Tuple<T1,T2>. Thông tin thêm về lớp học Tuple tại MSDN.

+6

.NET 4 chỉ: http://msdn.microsoft.com/en-us/library/dd268536.aspx#versionsTitleToggle – Hound

+1

Vì lợi ích của đối số. Tại sao sử dụng Tuple thay vì lớp ghép nối của riêng bạn? –

+0

@korbinian - đó là những gì tôi nghĩ, nhưng MSDN đã ném tôi đi bằng cách bao gồm một liên kết đến "phiên bản trước" bao gồm .NET 3.5. Thật không may, những nhận xét đó (mà tôi đã không nhìn) trung thực chỉ ra thực tế rằng nó chỉ NET 4. – tvanfosson

1

Đầu tiên là phương pháp ưa thích của tôi, vì một chuỗi có thể dài hơn phương thức thứ hai với thứ tự thứ hai - nó không duy trì ánh xạ 1: 1 bắt buộc.

1

Theo ý kiến ​​của tôi, tùy chọn thứ hai cung cấp cho cả bạn và khách hàng nhiều việc phải làm hơn. Tùy chọn đầu tiên là an toàn hơn và khó khăn hơn để có được sai. Tôi sẽ chọn tùy chọn đầu tiên hoặc một cái gì đó giống như nó mỗi lần.

+0

Vâng, đó là những gì tôi đã nói. –

0

Tôi nghĩ rằng bạn phải đi với tùy chọn 1. Phải có mối quan hệ rõ ràng liên quan hoặc bạn chỉ yêu cầu sự cố.

5

Nếu bạn có quyền truy cập vào nó, hãy sử dụng Tuple<T, R>. Nếu không, bạn chỉ cần viết một lớp chung là Tuple hoặc Pair của riêng bạn. Tôi sẽ tránh sử dụng KeyValuePair, chỉ vì nó dài dòng và có liên kết với Dictionary.

+0

Ngoài ra, cuối cùng tôi đã kiểm tra, KeyValuePair không tuần tự hóa thành XML, vì vậy đó là một lý do tốt để không sử dụng nó nếu điều đó quan trọng đối với bạn. – AaronLS

5

Tôi thích KeyValuePair của hai bạn đề cập vì nó mang tính biểu cảm hơn và giữ mối quan hệ giữa các đối tượng.

Nhưng tôi thà tạo một lớp có tham chiếu đến cặp của bạn. Điều này là dễ đọc hơn theo ý kiến ​​của tôi, và nó không bao giờ đau khổ để tạo ra một lớp học thêm hoặc cấu trúc để thể hiện hành động thực tế của bạn.

(Pseudo-code)

class MyPair 
{ 
    public TypeA One; 
    public TypeB Two; 
} 

MyClass(IEnumerable<MyPair> objects) 

Có đề cập đến Tuple<,> trong một số câu trả lời, mà là như có thể đọc được như KeyValuePair, nhưng linh hoạt hơn vì nó có thể chứa nhiều hơn hai tham số.

[Edit - sâu sắc hơn về Tuples/classes sau một giấc ngủ đêm tốt]

To Tuple or Not To Tuple

+0

Tại sao MyPair nên thực hiện IEnumerable? –

+0

@ Alex, bởi vì nó không nên :) Bạn đúng, và tôi dường như cần ngủ. –

+0

Đừng lo lắng về nó matey - Tôi có thể liên quan đến điều ngủ :) –

0

Tôi sẽ sử dụng phiên bản thứ hai (vì nó đơn giản hơn) + nhận xét + kiểm tra tĩnh/động. Nếu bạn có thể sử dụng các hợp đồng mã, hãy thử đảm bảo rằng các bộ sưu tập có cùng chiều dài, không phải là rỗng. Nếu không, hãy làm tương tự với Debug.Assert cũng như if ... throw ArgumentException. Ngoài ra, bạn có thể tạo đối tượng của riêng bạn có chứa các cặp, nhưng sau đó nó trở nên khó khăn hơn nếu bạn muốn sử dụng generics cho các thành viên của cặp. Ngoài ra, khi bạn tạo một đối tượng được lưu trữ trong vùng chứa, bạn phải triển khai đúng GetHashCode, Equals, v.v. Cuốn sách "Hiệu quả C#" đầu tiên có một mục về điều này.

Theo nguyên tắc chung, tôi không muốn ghi đè chữ ký phương thức quá mức.

0

Tôi thường cung cấp cả hai, với hàm tạo KeyValuePair ủy nhiệm vào hàm tạo 2-arg. Tốt nhất của cả hai thế giới.

+0

Chỉ cần tò mò - Tôi hiểu làm thế nào bạn có thể đi từ hai phương pháp arg để một arg bằng cách làm một Zip - làm thế nào để bạn làm điều đó theo cách khác xung quanh? –

+0

MyClass công cộng (KeyValuePair pair): this (pair.Key, pair.Value) {} – benjismith

1

Tôi chắc chắn muốn ưu tiên đầu tiên. Như bạn nói, sự tương quan trong rõ ràng, và nó ít dễ bị lỗi hơn thứ hai, nơi bạn cần kiểm tra rằng cả hai bộ sưu tập có cùng độ dài. Tất nhiên, nó thực sự có thể thích hợp để cung cấp/cả hai/cách, tùy thuộc vào lớp học thực tế bạn đang xây dựng.

Một điều, nếu bạn sử dụng .NET 4.0, tôi khuyên bạn nên sử dụng Tuple<T1, T2> thay vì KeyValuePair.

0

Tôi thích phương pháp đầu tiên vì hai lý do.

  1. Nếu họ đang lưu trữ mối quan hệ của mình trong từ điển <> đã có, họ chỉ có thể tắt từ điển - không cần thêm mã.

  2. Nếu họ đang sử dụng lưu trữ tùy chỉnh riêng của họ sau đó đem lại cho bạn KeyValuePairs trong một IEnumerable là thực sự dễ dàng với báo cáo kết quả năng suất

Something như thế này:

IEnumerable<KeyValuePair<Object,Object>> GetMappedPairs() 
{ 
    foreach(var pair in _myCustomData) 
    { 
     yield return new KeyValuePair{Key = pair.ID, Value = pair.Data}; 
    } 
} 

Lựa chọn số 2 không phải là dễ hiểu bởi các nhà phát triển bằng cách sử dụng phương pháp của bạn vì vậy nó sẽ yêu cầu tài liệu và ý kiến ​​để giải thích cách sử dụng nó.

Ngẫu nhiên, bạn có thể sẽ được phục vụ tốt nhất bằng cách tuyên bố phương pháp của bạn như một generic thay vì cứng mã hóa KeyValuePair

MyClass<TKey,TValue>(IEnumerable<KeyValuePair<TKey,TValue>> pairs); 
0

Nó có thể là giá trị xem xét lý do tại sao bạn tiếp xúc với một đếm được ở tất cả. Bạn có thể sử dụng phương thức Add (Object a, Object b) để ẩn hoàn toàn cách xử lý nội bộ của bạn với các cặp. Sau đó, khách hàng có thể thiết lập các phương tiện riêng của họ để bổ sung các mối quan hệ với nó như một trong hai bộ hoặc đơn lẻ.

Tất nhiên nếu bạn vẫn cần một phương pháp lấy số đếm, thì tùy chọn đầu tiên có lẽ là tốt nhất: một mối quan hệ rõ ràng. Nhưng bạn xem xét việc sử dụng hoặc tạo một Tuple hoặc Pair type để sử dụng thay vì KeyValuePair, giả sử mối quan hệ giữa chúng không phải là một trong những tính năng Key to Value.

0

Bây giờ, nếu bạn đã làm điều gì đó như , thì sao?

// The client can choose to put together an IEnumerable<...> by hand...  
public MyClass(IEnumerable<KeyValuePair<object, object>> pairs) 
{ 
    // actual code that does something with the data pairs 
} 

// OR the client can pass whatever the heck he/she wants, as long as 
// some method for selecting the Xs and Ys from the enumerable data is provided. 
// (Sorry about the code mangling, by the way -- just avoiding overflow.) 
public static MyClass Create<T> 
(IEnumerable<T> source, Func<T, object> xSelector, Func<T, object> ySelector) 
{ 
    var pairs = source 
     .Select(
      val => new KeyValuePair<object, object>(
       xSelector(val), 
       ySelector(val) 
      ) 
     ); 

    return new MyClass(pairs); 
} 

này sẽ cho phép khách hàng để viết mã như thế này:

// totally hypothetical example 
var stockReturns = StockReturns.Create(prices, p => p.Close, p => p.PrevClose); 
Các vấn đề liên quan