寻找访问词典的语法快捷方式

时间:2010-03-16 16:56:19

标签: c# dictionary

我有一个包含Dictionary的抽象基类。我希望继承的类能够使用方便的语法访问字典字段。目前我有很多这样的代码:

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)中做这样的事情?

4 个答案:

答案 0 :(得分: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"];

答案 1 :(得分: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.");
}

答案 2 :(得分:-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且需要特定转换的类型)。

答案 3 :(得分:-1)

假设它并不总是你想要的int(如果是,那么为什么它不是Dictionary<string, int>?) - 我觉得这样的事情起作用并且非常接近:

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

这结合了以下事实:标识符可以以@作为前缀(它通常是可选的,但如果您的标识符是reserved keyword,则需要它,如int或string),其默认索引参数来自{{ 3}}

它确实需要使用另一个类来获取索引 - 尽管如果你想使用parens而不是方括号作为键名,你可以改用方法:

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));
   }
}  

阅读Andrew Hare's answer后 - 如果您未与@绑定,则_是合法标识符。将它与索引器结合起来就可以得到:

int i = _["key"];