如何在非类型化 IEnumerable 中支持字典和列表

How to support Dictionary and List in untyped IEnumerable

我有一个 "ComboBox" UserControl/Widget/View ( Picker),其中 ItemsSource 可以是列表或字典。 ComboBox 具有以下属性和它们之间的同步:

SelectedItem : object;
SelectedValue : object;
SelectedValuePath : string;
DisplayMemberPath : string;

"ComboBox" (Picker) 也有一些内部属性:

SelectedIndex : int;
Items : IList<string>;

ItemsSource 当前未键入 IEnumerable - 这样您就可以使用 DictionaryList 从 XAML 填充它.

当我尝试根据 SelectedIndex 设置 SelectedItem 时出现问题。 我不知道 Dictionary 的类型(即 Dictionary<int, string>)。使用列表可以正常工作:

this.SelectedItem = ((IEnumerable<object>)this.ItemsSource).ToArray()[this.SelectedIndex];

为了使用 Enumerable.ElementAt({index}) 我必须将 IEnumerable 转换为类型化字典。它不适用于 IDictionary/Dictionary,而且我似乎也无法转换为 Dictionary<dynamic, dynamic>

此外,我需要从 SelectedItem 更改同步回 SelectedIndex,这会出现类似的问题。有了一个列表,我就可以做到

this.SelectedIndex = this.ItemsSource.IndexOf(this.SelectedItem);

这不会为字典抛出异常,但 returns -1.

我可以给你一个想法,但这绝不是充分的证据,我还没有在你的案例中尝试过。

假设我有

Dictionary<int,string> test = new Dictionary<int,string>();

添加了 KVP 值

test.Add(1,"1");
test.Add(2,"2");
test.Add(3,"3");

然后您可以使用反射生成一个 IList,然后您可以使用 IndexOf 或使用索引器。 如下图

if (test is IDictionary)
{
    var list = GetListFromDictionary(test);
    if (list != null)
    {
        Console.WriteLine(list[1]);
        Console.WriteLine(list.IndexOf(new KeyValuePair<int, string>(2,"2")));
    }
}

随着 GetListFromDictionary

public IList GetListFromDictionary(IDictionary dict)
{

        var type = dict.GetType();
        var newType = typeof(KeyValuePair<,>);
        var typeArgs = type.GetGenericArguments();
        var contructed  = newType.MakeGenericType(typeArgs);        
        var toListMethod = typeof(Enumerable).GetMethods().First(meth => meth.Name == "ToList");
        var method = toListMethod.MakeGenericMethod(new[] { contructed });
        return method.Invoke(null, new object[] { dict}) as IList;

}

// PCL版本

    public IList GetListFromDictionary(IDictionary dict)
    {

        var type = dict.GetType();
        var newType = typeof(KeyValuePair<,>);
        var typeArgs = type.GenericTypeArguments;
        var contructed = newType.MakeGenericType(typeArgs);
        var toListMethod = typeof(Enumerable).GetRuntimeMethods().First(meth => meth.Name == "ToList");
        var method = toListMethod.MakeGenericMethod(new[] { contructed });
        return method.Invoke(null, new object[] { dict }) as IList;

    }