2010-06-10 28 views
6

Tôi muốn kiểm tra nếu một id chưa được biết hoặc, nếu nó được biết, nếu giá trị liên quan đã thay đổi. Tôi hiện đang sử dụng mã tương tự như thế này, nhưng khó hiểu đối với những người không quen với mẫu. Bạn có thể nghĩ ra một cách để làm cho nó dễ đọc hơn trong khi vẫn giữ nó ngắn trong LOC?Tôi làm cách nào để làm cho mã từ điển TryGetValue này dễ đọc hơn?

string id; 
string actual; 
string stored; 

if (!someDictionary.TryGetValue (id, out stored) || stored != actual) { 
    // id not known yet or associated value changed. 
} 

Trả lời

1

Có vẻ tốt với tôi ... đọc dễ dàng như bất kỳ điều kiện khác 2 câu lệnh if. Về điều duy nhất tôi có thể thay đổi là lật các phủ định cho một lối ra sớm:

if (someDictionary.TryGetValue(id, out stored) && stored == actual) { 
    return; 
} 
// store new value 

Tôi không thấy bất kỳ sự nhầm lẫn nào, chưa bao giờ nghĩ nó là một thành ngữ đặc biệt phiền hà, và humbly cho rằng những người phát triển C# bị nhầm lẫn bởi nó quen với nó. Đó là phổ biến, succint, và cho càng nhiều LOC cho vấn đề như nó xứng đáng. Biến nó thành 10 dòng mã làm cho nó cách quá quan trọng.

Nếu tôi thường xuyên sử dụng, phương pháp mở rộng có tên là ContainsEqualValue sẽ phù hợp - nhưng tôi sẽ sử dụng cùng một mã chính xác trong phương pháp tiện ích như bạn có.

+2

Nó không hoàn toàn giống với bất kỳ câu lệnh 2 điều kiện nào vì nó đòi hỏi phải khai báo trước tham số 'out'. "... quen với nó?" Nó không phải là devs là "nhầm lẫn", * mỗi se *. Ngay cả một lập trình viên kỳ cựu, người đọc từ trái sang phải phải trả lại, ra, và chỉ để đọc điều này, và sắp xếp một số yếu tố trong tâm trí trong khi làm như vậy. Đây không phải là một nhiệm vụ * cứng *, nhưng nó cũng không phải là tự nhiên. Đây là phần mã thủ tục và giới thiệu cơ hội cho sự lặp lại và lỗi. Khả năng đọc là một mối quan tâm chính đáng và 'TryGetValue' với kết quả' bool' là yếu về mặt ngữ nghĩa. – Jay

+0

@Jay: Tại sao bạn kiểm tra việc khai báo biến số ngoài? Nó rõ ràng là có (hoặc trình biên dịch sẽ khiếu nại), và bạn không nên quan tâm những gì giá trị đã được trước (vì nó là một param ra, giá trị không được sử dụng bởi các chức năng). Điều này thực sự là tất cả về 'out' thay vì điều kiện? Về những điểm duy nhất tôi sẽ thừa nhận trên tuyên bố này là 1.) tác dụng phụ là trong điều kiện, và 2.) các điều kiện là phụ thuộc vào thứ tự. 'bool Try * (out)' là một thành ngữ được thiết lập tốt trong BCL mà tôi mong đợi devs to grok, vì vậy tôi tha thứ cho cái đầu tiên. –

+0

@Jay: Nhận xét của bạn là "tại chỗ". Theo tôi, không ai trong số các câu trả lời địa chỉ có thể đọc được. Đó là lý do tại sao tôi đóng góp mã được đề xuất của tôi. – AMissico

4

Vì vậy, tôi có thể sẽ phá vỡ nó và đặt tên có ý nghĩa. Đây là cách đọc nhiều hơn, nhưng bạn không cần nói nhiều trong nhận xét:

bool isKnown = someDictionary.TryGetValue (id, out stored); 
// can only change when it is known 
bool valueChanged = isKnown && stored != actual; 

// quite self-explanatory, isn't it? 
if (!isKnown || valueChanged) 
{ 

} 
+0

Nó được khởi tạo, từ khóa 'out' kết hợp với các quy tắc ưu tiên toán tử đảm bảo điều đó. – mafu

+0

Tham số ngoài phải được đặt bên trong hàm để TryGetValue khởi tạo nó. –

+1

'được lưu trữ' luôn được khởi tạo sau khi gọi đến' TryGetValue'. Đó là quy tắc của tham số 'out'. Rõ ràng, nó không phải là một giá trị hợp lệ. – leppie

2

Tính hai mặt.

if (!(someDictionary.TryGetValue (id, out stored) && stored == actual)) ... 

Không chắc chắn nếu nó dễ đọc hơn ... nhưng bạn nên biết.

+2

Tôi nghĩ rằng điều này khó đọc hơn bản gốc. – mafu

+0

-1 để không đọc được. Tôi sẽ gặp khó khăn khi hiểu và sửa những tuyên bố này. Đặc biệt, vì 'được lưu trữ' là' out', bạn sử dụng nó trong cùng một câu lệnh. Bạn đang buộc tôi phải đọc từng phần tử để hiểu điều gì đang xảy ra. – AMissico

+0

@AMissico: những cạm bẫy của mã thủ tục :) – leppie

3

quấn từng phần của || vào phương pháp hoặc tài sản riêng của mình, hơn là bạn có thể viết nó như thế này

if (IdIsNew() || IdChanged()) 
+0

Tôi muốn tránh viết nhiều dòng mã. – mafu

+2

Tôi sẽ không tạo các phương thức mới trừ khi chúng sẽ loại bỏ bất kỳ lỗi nào có thể xảy ra. Tôi sẽ tạo ra các phương thức mới nếu nó tăng khả năng đọc và bảo trì. – AMissico

1

Tôi muốn một phương pháp mới:

public bool ShouldSetValue(Dictionary someDictionary, object id,object actualValue) 
{ 
    string stored; 

    if (someDictionary.TryGetValue (id, out stored)) 
    { 
     if (stored != actualValue) 
      return true; 
    } 
    else 
    { 
     return true; 
    } 
} 

sau đó trong phương pháp hiện tại tôi muốn chỉ:

if (ShouldSetValue(someDictionary,id,actual)) 
{ 
    someDictionary[id]=actual; 
} 
+2

'AddValue' là một tên khủng khiếp cho phương pháp mà không thực sự làm/biến đổi bất cứ điều gì. 'CanAddValue' có thể là tên tốt hơn. – leppie

+0

Ý tưởng hay. Có lẽ là một phương pháp mở rộng cho từ điển? Và việc đặt tên là lạ. – mafu

+0

đặt tên đồng ý là lạ. đã thay đổi nó.Và có bạn có thể thực hiện nó như là một phương pháp mở rộng trên từ điển, mà có lẽ sẽ làm cho nó một chút đẹp hơn ... –

5

Bạn có thể viết một phương thức tiện ích mở rộng có tên tốt:

public static class Utility 
{ 
    public static bool ValueChangedOrUnknown(this Dictionary<string, string> dictionary, string id, string actual) 
    { 
     string stored = null; 
     return (!dictionary.TryGetValue(id, out actual) || stored != actual); 
    } 
} 

để sau này bạn có thể sử dụng

string id; 
string actual; 

if (someDictionary.ValueChangedOrUnknown(id, actual) { 
    // id not known yet or associated value changed. 
} 
+1

+1. Tôi ghét các tham số "out", và tôi thường quấn bất kỳ truy cập nào vào TryGetValue bằng một phương thức mở rộng (ví dụ như TryGetValueOrDefault để trả về trực tiếp, hoặc null hoặc 0 nếu nó không thể tìm thấy mục nhập). –

+0

"out" = mã không rõ ràng – AMissico

0

Một phương pháp mở rộng sẽ được slick:

public static class DictionaryExtensions 
{ 
    public static bool ShouldAddValue<TKey, TValue>(this Dictionary<TKey, TValue> someDictionary, TKey id, TValue actual) 
    { 
     TValue stored; 
     return (!someDictionary.TryGetValue(id, out stored) || !stored.Equals(actual)); 
    } 
} 

Cách sử dụng:

someDictionary.ShouldAddValue("foo", "bar") 
0

Nếu bạn có nghĩa là bạn phải làm điều này nhiều lần, và nó dài và xấu, trừu tượng logic sang một lớp khác và sử dụng một phương thức mở rộng.

public static class DictionaryExtensions 
{ 
    public static DictionaryChecker<TKey,TValue> contains<TKey,TValue>(this IDictionary<TKey,TValue> dictionary, TValue value) 
    { 
     return new DictionaryChecker<TKey,TValue>(value, dictionary); 
    } 
} 

public class DictionaryChecker<TKey,TValue> 
{ 
    TValue value; 
    IDictionary<TKey,TValue> dictionary; 

    internal DictionaryChecker(TValue value, IDictionary<TKey, TValue> dictionary) 
    { 
     this.value = value; 
     this.dictionary = dictionary; 
    } 

    public bool For(TKey key) 
    { 
     TValue result; 
     return dictionary.TryGetValue(key, out result) && result.Equals(value); 
    } 
} 

Bây giờ thay thế mã của bạn với:

if(!someDictionary.contains(actual).For(id)){ 
    // id not known yet or associated value changed. 
} 
+2

Quá nhiều mã. Quá phức tạp cho một cái gì đó rất đơn giản. – AMissico

+0

@AMissico "Quá nhiều mã" là chủ quan. Nó phụ thuộc vào miền và nhu cầu sử dụng. Điều này chỉ được cung cấp như một cách tiếp cận có lợi cho dễ đọc trong sử dụng, và sẽ chỉ có ý nghĩa nếu đây là một kiểm tra mà đã được thực hiện ở nhiều nơi. Khả năng đọc giảm xuống khi số lượng tham số tăng lên; đây là một cách để giảm thiểu sự suy thoái đó, nếu bạn thấy giá trị trong việc làm như vậy. – Jay

+0

Tôi hoàn toàn đồng ý với bạn, đó là lý do tại sao tôi không bỏ phiếu. Tôi ủng hộ "nạc" để cách tiếp cận của bạn có vẻ hơi nặng vì bạn đã thêm mười dòng mã, không làm cho nó dễ đọc hơn và không thay đổi câu lệnh khó hiểu. – AMissico

0
public T GetValue(int id, object actual) 
{ 
    object stored; 
if (someDictionary.TryGetValue (id, out stored) || stored == actual) 
    return stored; 
    return new object(); 
} 
0

Mặc dù tôi nhận ra rằng mẫu "thử" là cần thiết, tôi không thích triển khai yêu cầu thông số "không tham gia". Nó sẽ có vẻ nhiều hơn nữa hữu ích có chức năng tương tự như TryGetValue:

  • TryGetDictValue (từ điển, key) trả về null nếu chìa khóa không có trong từ điển
  • TryGetDictValue (từ điển, chìa khóa, defaultValue) trả defaultValue nếu chìa khóa không có trong từ điển
  • TryGetDictValue (từ điển, chìa khóa, valueReturningDelegate) gọi các đại biểu được cung cấp nếu chìa khóa không có trong từ điển và trả về kết quả của nó

trong mọi trường hợp, các kiểu trả về của kết quả sẽ là dữ liệu của từ điển.

Thật tệ khi không có cách nào lẻn vào một cỗ máy thời gian và làm những thứ như vậy là các phương pháp của Từ điển. Mặt khác, người ta có thể thực hiện chúng như các hàm tĩnh lấy từ điển làm tham số đầu tiên.

+0

Điều này vẫn có thể được thực hiện như là phương pháp mở rộng, đó có thể là những gì bạn có ý nghĩa với bình luận cuối cùng của bạn. – Dykam

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