【问题标题】:Enumerate keys and values of IDictionary when I don't know type of values当我不知道值的类型时,枚举 IDictionary 的键和值
【发布时间】:2016-08-05 07:41:52
【问题描述】:

我有一个对象的引用。我知道它符合

IDictionary<string, T> 

对于某些类型 T。(它可能不符合普通 IDictionary 或 IReadyOnlyDictionary)。我所知道的关于 T 是它来自对象。如何获取它的键,并获取键的值? (我可以将值作为对象返回,而不是作为 T。我也可以从不知道 T 是什么。)

我想写,但写不出来,是这样的:

public void SomeMethod(object reallyADict) { // reallyADict implements IDictionary<string, T>.
  foreach (string key in reallyADict.Keys) {
    object value = reallyADict[key];
    // . . .
  }
}

**

根据请求,下面是一个示例类。

using System;
using System.Collections.Generic;
using System.Collections;

namespace My.Collections
{
  public class WrappedDictionary: IDictionary<string, int>
  {
    public WrappedDictionary() {
      this.InnerDictionary = new Dictionary<string, int>{ {"one", 1}, {"two", 2 }};
    }
    private Dictionary<string, int> InnerDictionary { get; set;}

    private ICollection<KeyValuePair<string, int>> InnerCollection {
      get {
        return this.InnerDictionary;
      }
    }


    #region IDictionary implementation
    void IDictionary<string, int>.Add(string key, int value) {
      this.InnerDictionary.Add(key, value);
    }
    bool IDictionary<string, int>.ContainsKey(string key) {
      return this.InnerDictionary.ContainsKey(key);
    }
    bool IDictionary<string, int>.Remove(string key) {
      return this.InnerDictionary.Remove(key);
    }
    bool IDictionary<string, int>.TryGetValue(string key, out int value) {
      return this.InnerDictionary.TryGetValue(key, out value);
    }
    int IDictionary<string, int>.this[string index] {
      get {
        return this.InnerDictionary[index];
      }
      set {
        this.InnerDictionary[index] = value;
      }
    }
    ICollection<string> IDictionary<string, int>.Keys {
      get {
        return this.InnerDictionary.Keys;
      }
    }
    ICollection<int> IDictionary<string, int>.Values {
      get {
        return this.InnerDictionary.Values;
      }
    }
    #endregion
    #region ICollection implementation
    void ICollection<KeyValuePair<string, int>>.Add(KeyValuePair<string, int> item) {
      this.InnerCollection.Add(item);
    }
    void ICollection<KeyValuePair<string, int>>.Clear() {
      this.InnerDictionary.Clear();
    }
    bool ICollection<KeyValuePair<string, int>>.Contains(KeyValuePair<string, int> item) {
      return this.InnerCollection.Contains(item);
    }
    void ICollection<KeyValuePair<string, int>>.CopyTo(KeyValuePair<string, int>[] array, int arrayIndex) {
      this.InnerCollection.CopyTo(array, arrayIndex);
    }
    bool ICollection<KeyValuePair<string, int>>.Remove(KeyValuePair<string, int> item) {
      return this.InnerCollection.Remove(item);
    }
    int ICollection<KeyValuePair<string, int>>.Count {
      get {
        return this.InnerCollection.Count;
      }
    }
    bool ICollection<KeyValuePair<string, int>>.IsReadOnly {
      get {
        return this.InnerCollection.IsReadOnly;
      }
    }
    #endregion
    #region IEnumerable implementation
    IEnumerator<KeyValuePair<string, int>> IEnumerable<KeyValuePair<string, int>>.GetEnumerator() {
      return this.InnerCollection.GetEnumerator();
    }
    #endregion
    #region IEnumerable implementation
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
      return (this as IEnumerable).GetEnumerator();
    }
    #endregion
  }
}

【问题讨论】:

  • 您是否尝试过将方法设为通用? SomeMethod&lt;T&gt;(IDictionary&lt;string,T&gt; reallyADict) 之类的东西?
  • 我引用了 realADict 作为对象,而不是 Dictionary.

标签: c# idictionary


【解决方案1】:

很遗憾,您不能将 reallyADict 转换为 Dictionary&lt;string,T&gt; 之类的东西,因为您需要特定的类型。

和 Manfred 的评论一样使用通用方法

public IEnumerable<T> SomeMethod<T>(Dictionary<string, T> dict)

这也是我的方法。但你说你真的只有字典object

所以我用反射解决了这个问题:

public IEnumerable<object> SomeMethod(object reallyADict)
{
    Type genericInterface = reallyADict?.GetType().GetInterface("IDictionary`2");

    PropertyInfo propKeys = genericInterface?.GetProperty("Keys");
    if (propKeys?.GetMethod == null) yield break;

    IEnumerable<string> keys = (IEnumerable<string>)propKeys.GetValue(reallyADict);

    PropertyInfo propIndex = genericInterface.GetProperty("Item");
    if (propIndex?.GetMethod == null) yield break;

    foreach (string key in keys)
        yield return propIndex.GetMethod.Invoke(reallyADict, new object[] { key });
}

此方法从reallyDict(如果有)获取Keys 属性并将其用作IEnumerable&lt;string&gt;

然后它遍历所有这些键并使用底层字典的 indexer 属性来返回值。索引器属性的名称为 Item

【讨论】:

  • @ManfredRadlwimmer No. GetMethodPropertyInfo 的属性。 MethodInfo 代表该属性的吸气剂。在该行中,我不想get getter(我已经在GetMethod 中拥有它),我只想invoke 那个getter。
  • 如果您使用的是较旧的 .NET 版本,您可以使用 GetGetMethod() 代替 GetMethod(从 4.5 开始提供)
  • @ManfredRadlwimmer 刚刚检查过,是的,GetGetMethod() 将返回 MethodInfo 作为 getter,但 GetMethod 只是一个返回相同的属性。你可以随意选择;)
  • 嗯,有趣的是,当我调用 realADict.GetType().GetRuntimeProperties() 时,我没有看到一个名为“Keys”的项目,但我确实看到了一个名为 System.Collections 的项目。 Generic.IDictionary.Keys,其中 T 是 T 的实际值。 . .
  • @WilliamJockusch 使用 IDictionary&lt;string,someType&gt; 的自定义实现对其进行了测试,并且运行良好。
猜你喜欢
  • 1970-01-01
  • 2020-02-25
  • 1970-01-01
  • 2015-06-27
  • 1970-01-01
  • 2019-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多