2013-03-28 40 views
6

Đầu tiên, xin lỗi tên khá buồn cười của câu hỏi của tôi. Tôi không phải là người bản xứ và tôi mất 10 phút để thể hiện suy nghĩ của mình trong vài nhân vật này.Từ điển với số lượng giới hạn các loại

Điều tôi đang cố làm là tạo từ điển trong C# cho phép giá trị là int, một số string hoặc bool. Điều đầu tiên tôi nghĩ đến là sử dụng Generics, nhưng theo như tôi biết, tôi chỉ có thể định nghĩa một kiểu như kiểu giá trị có thể, chứ không phải "là một trong số đó". Sử dụng object cũng sẽ có thể, nhưng boxing có vẻ là một kẻ giết người thực hiện khá.

Có cách nào để thực hiện việc này không?

Dưới đây là một ví dụ về những gì đã đến với tâm trí tôi:

Dictionary<string, (string, int, bool)> foo = new Dictionary<string, (string, int, bool)>(); 
foo.Add("key1", "Hello, World!"); //Correct - Value is a string 
foo.Add("key2", 37); //Correct - Value is an int 
foo.Add("key3", true); //Correct - Value is a boolean 
foo.Add("key4", new Foobar()); //Compiler error - Value is a Foobar 

mục tiêu cuối cùng của tôi là để cung cấp một thư viện cho các nhà phát triển khác. Tính năng này sẽ cho phép chúng xác định "biến" trong thời gian chạy và cung cấp cho chúng một loại.

Edit: // Firefox' about: config trang có cái gì đó rất gần với những gì tôi muốn đạt được

+2

Tôi đã chỉnh sửa tiêu đề của bạn. Vui lòng xem, "[Câu hỏi có nên bao gồm" thẻ "trong tiêu đề của họ không?] (Http://meta.stackexchange.com/questions/19190/)", trong đó sự đồng thuận là "không, họ không nên". –

+0

Cảm ơn rất nhiều. Tôi đã nhìn thấy điều này khá thường xuyên và nghĩ rằng đó là thực tế phổ biến. –

+0

Vui lòng đọc liên kết tôi đã bao gồm trong nhận xét. Nó không phải là một thực hành tốt, và tôi sửa nó khi tôi nhìn thấy nó. –

Trả lời

6

Tại sao không tạo ra một lớp mới tươi mà thực hiện các IDictionary và sử dụng một từ điển như là một biến tư nhân.

Sau đó, trong phương pháp add, bạn có thể cung cấp logic riêng của bạn và không phù hợp

Mẫu mã

public class MyDic : IDictionary<object, object> 
{ 
    private Dictionary<object, object> privateDic= new Dictionary<object,object>(); 


    public void Add(object key, object value) 
    { 
     if (value.GetType() == typeof(string)) 
      throw new ArgumentException(); 
     privateDic.Add(key, value); 
    } 
    //Rest of the interface follows 
} 
+3

Tùy thuộc vào số lượng mã này sẽ thay đổi, bạn có thể cung cấp 3 quá tải riêng biệt cho phương thức 'Thêm', chấp nhận' giá trị' với loại 'int',' chuỗi' hoặc 'bool' tương ứng. Bằng cách đó, gõ đúng đắn được kiểm tra tại thời gian biên dịch, không phải lúc chạy. – dialer

+0

Đây có lẽ là cách tốt nhất để đi. Cảm ơn rất nhiều –

+0

@dialer: Giải pháp của bạn rõ ràng có lợi thế về việc kiểm tra thời gian biên dịch. tôi không biết nếu david cần kiểm tra thời gian chạy như tiêm các loại và –

0

tôi sẽ đề nghị để:

  1. Tạo một kiểu cơ sở cho các giá trị từ điển của bạn ví dụ MyDictionaryBaseType
  2. Mở rộng loại cơ bản này cho từng loại giá trị từ điển bạn có, ví dụ: StringDictionryType: MyDictionaryBaseType, IntegerDictionryType: MyDictionaryBaseType ... v.v.
  3. Tạo loại từ điển chung với MyDictionaryBaseType và giới hạn loại để mở rộng loại cơ sở này.

Bằng cách này bạn giới hạn dictionry của bạn để ba loại specifed

+0

Có thể ai đó vui lòng giải thích lý do tại sao điều này đã được giảm giá? –

+0

@DavidStockinger Tôi đoán vì nó sẽ buộc bạn phải tạo các kiểu của riêng bạn cho 'int',' bool' và 'string' để hoạt động. Về mặt lý thuyết (tức là khác hơn thế), nó là một giải pháp rất tốt và sạch sẽ. – dialer

0

Bạn có thể đặt các giá trị vào wrapper classs như thế này:

class Value 
{ 
} 

class TypedValue<T> : Value 
{ 
    public T Val; 
} 

class IntValue : TypedValue<int> 
{ 
} 

class StringValue : TypedValue<string> 
{ 
} 

class BoolValue : TypedValue<bool> 
{ 
} 

Dictionary<string,Value> foo; 

foo.Add("key1", new StringValue{Val="Hello World!"}); 

Một khả năng khác là sử dụng từ điển và thực hiện kiểm tra thời gian chạy cho các loại đúng hoặc sai được thêm vào. Tôi không nghĩ rằng có một giải pháp mà không liên quan đến quyền anh.

0

Những gì bạn đang cố gắng hoàn thành không an toàn kiểu khi nó đứng. Ví dụ, giả sử bạn có một từ điển như:

var foo = new Dictionary<string, (string, int, bool)>(); 
var x = foo["key1"]; 
// What type is x? How could the compiler know? 

Một ý tưởng sẽ được đưa ra một lớp container có sức chứa một trong hai string, int, hoặc bool.

public class StringIntBool { 
    private bool _isSet; 
    private bool _isString; 
    public bool IsString { 
     get { return _isString; } 
    } 
    // ... 

    private string _innerString; 
    public string InnerString { 
     get { 
      return _innerString; 
     } 
     set { 
      if (_isSet) { 
       throw new Exception("StringIntBool is already set"); 
      } 
      _isSet = true; 
      _isString = true; 
      _innerString = value; 
     } 
    } 

    // etc... 
} 

Điều này khá xấu và không thực sự mang lại nhiều lợi ích.Thay vào đó, bạn có thể lưu trữ tất cả ba giá trị là object s và sau đó sử dụng kỹ thuật/thư viện như Functional C# để thực hiện khớp mẫu, giống như nhiều ngôn ngữ chức năng có thể.

object x = "str"; 
int res = x.Match() 
    .With<string>(s => s == "str" ? 10 : 20) 
    .With<int>(i => i) 
    .With<bool>(b => b ? 50 : 60) 
    .Return<int>(); 

Mô hình lập trình này thực sự khá phổ biến ở một số ngôn ngữ chức năng nhất định. Ví dụ, trong SML, bạn có thể định nghĩa một kiểu dữ liệu, và sau đó mô hình phù hợp với nó khi cần thiết.

(* StringIntBool *) 
datatype sib = SibString of string | SibInt of int | SibBool of bool 

val x = (* some instance of sib *) 
val y = case x of 
    SibString s => if s = "hello" then 50 else -50 
    | SibInt i => i 
    | SibBool b => if b then 10 else 20 
+0

Tôi nghĩ rằng bạn có thể làm nhiều hơn hoặc ít hơn cùng một điều với các công đoàn phân biệt trong F # (Tôi biết câu hỏi này là về C#) – JerKimball

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