2012-05-02 22 views
6

Tôi muốn một hàm trợ giúp tra cứu đã nhập cho một bộ sưu tập không đồng nhất: Nó sẽ trả về một cấu trúc hoặc một lớp, nếu không thì không tìm thấy mục đó. Dưới đây là một ví dụ bằng cách sử dụng tra cứu bộ sưu tập tầm thường, nhưng nó có thể là một cuộc gọi cơ sở dữ liệu hoặc bất cứ điều gì.Làm thế nào để thực hiện phương pháp tìm kiếm bộ sưu tập chung có thể trả về cấu trúc lớp hoặc có thể null?

Có cách nào để đạt được điều này với một chữ ký phương pháp duy nhất không?

public T GetClass<T>(string key) where T : class 
    { 
     object o; 
     if (Contents.TryGetValue(key, out o)) 
     { 
      return o as T; 
     } 
     return null; 
    } 

    public T? GetStruct<T>(string key) where T : struct 
    { 
     object o; 
     if (Contents.TryGetValue(key, out o)) 
     { 
      if (o is T) 
      { 
       return (T?) o; 
      } 
     } 
     return null; 
    } 

Những gì tôi đã cố gắng:

  • Tôi hiểu rằng những hạn chế chung không thể được sử dụng để disambiguate quá tải. Vì vậy, tôi không thể chỉ đơn giản là cung cấp cho hai phương pháp này cùng tên.
  • Trả lại (Default) T không phải là một tùy chọn vì 0 là giá trị int hợp lệ.
  • Tôi đã thử gọi bằng <int ?> làm loại, nhưng như được thảo luận, Nullable<T> không phải là loại tham chiếu.

Có cách nào để cho biết rằng tôi sẽ trả về một hộp được đóng hộp không?

Trả lời

3

Phương pháp sau đây làm việc cho cả hai lớp và cấu trúc nullable:

public static T GetValue<T>(string key) 
{ 
    object o; 
    if (Contents.TryGetValue(key, out o)) 
    { 
     if (o is T) 
     { 
      return (T)o; 
     } 
    } 
    return default(T); 
} 

Cách sử dụng:

int? result1 = GetValue<int?>("someInt"); 
string result2 = GetValue<string>("someString"); 

Thông báo như thế nào ? là một phần của đối số kiểu chung chung và không được định nghĩa theo phương pháp trên kiểu trả về.

+3

tôi nửa như thế này - nhưng nó * cho phép * bạn gọi nó là 'getClass ' và trở về 0 cho " tìm thấy với giá trị 0 "và" không tìm thấy "không thể phân biệt được. Thật vậy, bạn có thể vô tình bỏ lỡ '?' Thứ hai trong việc sử dụng mẫu của bạn và nhận được một lỗi khá tinh tế. ('result1' sẽ * không bao giờ * là null, nhưng bạn sẽ mong đợi nó là) –

+0

Tôi nghĩ rằng mặc định cho int? là null – akatakritos

+0

Nhưng nếu giá trị bạn đang tìm kiếm là một int thường xuyên: tôi nghĩ rằng (o là int?) sẽ thất bại bc int? không phải là một int. – akatakritos

6

Có cách nào để đạt được điều này bằng chữ ký phương thức đơn không?

Có cách horrible (thực sự ghê tởm) để thực hiện bằng cách sử dụng các tham số tùy chọn để mã gọi có thể trông giống nhau trong cả hai trường hợp. Đó là icky mặc dù.

Options:

  • Return một Tuple<T, bool> thay vì sử dụng vô hiệu
  • Sử dụng một tham số out (như int.TryParse vv)
  • Sử dụng tên phương pháp khác nhau

Lưu ý rằng bằng cách báo hiệu sự vắng mặt của một giá trị riêng biệt, bạn có thể làm cho kết quả "được tìm thấy" hợp lệ, đôi khi có thể hữu ích đôi khi là null. Hoặc bạn có thể muốn đảm bảo rằng nó sẽ không bao giờ được trả lại.

Nếu bạn thực sự muốn sử dụng tính vô hiệu, tôi sẽ chọn tùy chọn cuối cùng. Tôi tin rằng nó sẽ làm cho mã của bạn rõ ràng hơn anyway. IMO, quá tải thực sự chỉ nên được sử dụng khi các phương thức thực hiện chính xác điều tương tự được thể hiện bằng các tham số khác nhau - trong khi trả lại Nullable<T> làm kiểu trả về trong một trường hợp và T. đường.

1

Điều này sẽ làm chính xác những gì bạn cần. Nếu kiểu được yêu cầu là một kiểu nullable, hãy kiểm tra kiểu cơ bản trước khi truyền.

public static T GetValue<T>(string key) 
{ 
    object o; 
    if (Contents.TryGetValue(key, out o)) 
    { 
     if (o is T || Nullable.GetUnderlyingType(typeof(T)) == o.GetType()) 
     { 
      return (T)o; 
     } 
    } 

    return default(T); 
} 

mã kiểm tra của tôi:

Contents.Add("a string", "string value"); 
Contents.Add("an integer", 1); 
Contents.Add("a nullable integer", new Nullable<int>(2)); 

// Get objects as the type we originally used. 
Debug.WriteLine(string.Format("GetValue<string>(\"a string\") = {0}", GetValue<string>("a string"))); 
Debug.WriteLine(string.Format("GetValue<int>(\"an integer\") = {0}", GetValue<int>("an integer"))); 
Debug.WriteLine(string.Format("GetValue<int?>(\"a nullable integer\") = {0}", GetValue<int?>("a nullable integer"))); 

// Get objects as base class object. 
Debug.WriteLine(string.Format("GetValue<object>(\"a string\") = {0}", GetValue<object>("a string"))); 
Debug.WriteLine(string.Format("GetValue<object>(\"an integer\") = {0}", GetValue<object>("an integer"))); 
Debug.WriteLine(string.Format("GetValue<object>(\"a nullable integer\") = {0}", GetValue<object>("a nullable integer"))); 

// Get the ints as the other type. 
Debug.WriteLine(string.Format("GetValue<int?>(\"an integer\") = {0}", GetValue<int?>("an integer"))); 
Debug.WriteLine(string.Format("GetValue<int>(\"a nullable integer\") = {0}", GetValue<int>("a nullable integer"))); 

// Attempt to get as a struct that it's not, should return default value. 
Debug.WriteLine(string.Format("GetValue<double>(\"a string\") = {0}", GetValue<double>("a string"))); 

// Attempt to get as a nullable struct that it's not, or as a class that it's not, should return null. 
Debug.WriteLine(string.Format("GetValue<double?>(\"a string\") = {0}", GetValue<double?>("a string"))); 
Debug.WriteLine(string.Format("GetValue<StringBuilder>(\"a string\") = {0}", GetValue<StringBuilder>("a string"))); 

Kết quả:

GetValue<string>("a string") = string value 
GetValue<int>("an integer") = 1 
GetValue<int?>("a nullable integer") = 2 

GetValue<object>("a string") = string value 
GetValue<object>("an integer") = 1 
GetValue<object>("a nullable integer") = 2 

GetValue<int?>("an integer") = 1 
GetValue<int>("a nullable integer") = 2 

GetValue<double>("a string") = 0 

GetValue<double?>("a string") = 
GetValue<StringBuilder>("a string") = 
+0

'(đối tượng) 42 là int?' Là đúng. Không cần cho '|| Nullable ... 'kiểm tra. – dtb

+0

Dang nó, đôi khi tôi ghét ma thuật biên dịch xung quanh nullable. Không có cấu trúc nào khác trả về true cho ''. –

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