2010-03-16 47 views
1

我有一個抽象基類,它包含一個字典。我希望繼承的類能夠使用方便的語法訪問字典字段。目前,我有很多這樣的代碼:尋找訪問字典的語法快捷鍵

string temp; 
int val; 
if (this.Fields.TryGetValue("Key", out temp)) { 
    if (int.TryParse(temp, out val)) { 
     // do something with val... 
    } 
} 

很顯然,我可以在實用功能包,但我想有一個很酷的,方便的語法來訪問詞典字段,我可以簡單地這樣說:

int result = @Key; 

有沒有辦法在C#(3.5)中做這樣的事情?

+2

你喜歡這種語法嗎? int result = Fields [key]; ? – 2010-03-16 16:59:19

+0

這是一個很好的例子,你*不想*使用TryParse()。你用它來捕捉用戶的錯誤,他們是正常的。你真的必須在這裏使用Parse()來捕捉編程錯誤。 TryGetValue出於同樣的原因是錯誤的。 – 2010-03-16 18:26:54

+0

爲什麼你的字典是私人的,不受保護是否有特殊原因? (假設它是私有的) – 2010-03-17 13:29:39

回答

4

您可以將索引器添加到您的類中,並將索引器的參數傳遞給字典。

class Foo 
{ 
    // Initialized elsewhere 
    Dictionary<String,String> Fields; 

    public Int32 this[String key] 
    { 
     String temp = null; 
     Int32 val = 0; 
     if (this.Fields.TryGetValue(key, out temp)) { 
      Int32.TryParse(temp, out val); 
     } 
     return val; 
    } 
} 

然後給叫foo你能做到這一點的Foo一個實例:

Int32 value = foo["Key"]; 
0

如何擴展方法?

public static int TryGetInt(this IDictionary dict, string key) 
{ 
    int val; 
    if (dict.Contains(key)) 
    { 
     if (int.TryParse((string)dict[key], out val)) 
      return val; 
     else 
      throw new Exception("Value is not a valid integer.");  
    } 

    throw new Exception("Key not found."); 
} 
+0

爲什麼要使用有意避免異常的方法,以後再拋出較少的描述性異常?整個方法體可以寫成'return int.Parse(dict [key]);'並且在無效值的情況下具有相同的行爲,但是更具描述性的例外。 – 2010-03-17 09:30:59

+0

這是一個很好的觀點。爲什麼如果底層模型會在相同情況下引發這些異常,那麼爲什麼會引發異常呢?這裏的底線是這個答案不是完美的解決方案;它只是將原始OP的代碼包裝到擴展方法中。您完全可以注意到這裏引發的不必要的例外,但是如果您能看到這一點,您肯定會注意到爲什麼他們在我的答案中。 – Codesleuth 2010-03-17 10:03:26

+0

這是如何「一個很酷,方便的語法」? – 2010-03-17 12:50:17

-1

越接近你可以得到一個不錯的語法使用擴展方法:

public static class MyDictExtensionMethods 
{ 
    public static T Get<T>(this Dictionary<string, object> dict, string key) 
    where T: IConvertible 
    { 
    object tmp; 
    if (!dict.TryGetValue(key, out tmp)) 
     return default(T); 
    try { 
     return (T) Convert.ChangeType(tmp, typeof(T)); 
    } catch (Exception) { 
     return default(T); 
    } 
    } 
} 

用法:類型:

int val = this.Fields.Get<int>("Key"); 

然後,您可以創建特定類型(即額外重載這不會實現IConvertible並需要特定的轉換)。

-1

假設它並不總是你想要一個int - 我認爲像這樣的工作,並非常接近得到(如果是的話,爲什麼不是一個Dictionary<string, int>?):

int i = @int["Key"]; 
string s = @string["Key"]; 
object o = @object["Key"]; 

這個結合了事實上標識符的前綴可以是@(通常是可選的,但如果標識符是reserved keyword,比如int或字符串,則需要它),默認索引參數爲Andrew Hare's answer

它確實需要另一個類,以用於獲取索引 - 但如果你想用括號而非方括號鍵名,你可以使用方法代替:

int i = @value<int>("Key"); 

實現會是這樣像:

class DerivedClass : BaseClass { 
    void Main() { 
     int i = @int["Key"]; 
    } 
} 

abstract class BaseClass { 
    private Dictionary<string, string> D { get; set; } 

    protected Indexer<int> @int = new Indexer<int>(s => int.Parse(s), this); 
    protected Indexer<string> @string = new Indexer<string>(s => s, this); 
    protected Indexer<object> @object = new Indexer<object>(s => (object)s, this); 

    protected class Indexer<T> { 
     public T this[string key] { 
      get { return this.Convert(this.BaseClass.D[key]); } 
     } 

     private T Convert(string value) { get; set; } 
     private BaseClass { get; set; } 

     public Indexer(Func<T, string> c, BaseClass b) { 
      this.Convert = c; 
      this.BaseClass = b; 
     } 
    }  
} 

或者,方法途徑:

class DerivedClass : BaseClass { 
    void Main() { 
     int i = @value<int>("key"); 
    } 
} 

abstract class BaseClass { 
    private Dictionary<string, string> D { get; set; } 

    protected T @value<T>(string key) { 
     string s = this.D[s]; 
     return Convert.ChangeType(s, typeof(T)); 
    } 
} 

在通過language spec閱讀之後 - 如果您未綁定到@,則_是合法標識符。結合索引器,你會得到:

int i = _["key"];