如何在非类型化 IEnumerable 中支持字典和列表
How to support Dictionary and List in untyped IEnumerable
我有一个 "ComboBox" UserControl/Widget/View (xamarin.forms Picker
),其中 ItemsSource 可以是列表或字典。 ComboBox 具有以下属性和它们之间的同步:
SelectedItem : object;
SelectedValue : object;
SelectedValuePath : string;
DisplayMemberPath : string;
"ComboBox" (Picker
) 也有一些内部属性:
SelectedIndex : int;
Items : IList<string>;
ItemsSource 当前未键入 IEnumerable
- 这样您就可以使用 Dictionary
或 List
从 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;
}
我有一个 "ComboBox" UserControl/Widget/View (xamarin.forms Picker
),其中 ItemsSource 可以是列表或字典。 ComboBox 具有以下属性和它们之间的同步:
SelectedItem : object;
SelectedValue : object;
SelectedValuePath : string;
DisplayMemberPath : string;
"ComboBox" (Picker
) 也有一些内部属性:
SelectedIndex : int;
Items : IList<string>;
ItemsSource 当前未键入 IEnumerable
- 这样您就可以使用 Dictionary
或 List
从 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;
}