我基本上想要这样做:
if(obj is IDictionary)
{
return "{" + string.Join(Environment.NewLine, ((IDictionary)obj).Cast<DictionaryEntry>().Select(e => string.Format(" {0}: {1}", PrettyString(e.Key), PrettyString(e.Value)))) + "}";
}
但我一直得到一个无效的演员。我能做到
foreach(DictionaryEntry e in (IDictionary)obj)
那为什么我不能这样做呢?
我觉得这很好奇。我写了一个扩展来解决这个问题:
static class EnumerableExt
{
public static IEnumerable<DictionaryEntry> Entries(this IDictionary dict)
{
foreach (var item in dict) yield return (DictionaryEntry)item;
}
}
然后我可以这样做:
((IDictionary)obj).Entries().Select(...)
奇怪的是,Resharper告诉我,我可以用这个替换我的扩展名:
return dict.Cast<DictionaryEntry>();
但是这引发了异常。这是Resharper中的一个错误吗?或Cast
如何运作?我认为Cast
将完全按照扩展程序的方式工作。
编辑:啊..我更仔细地阅读了this answer。还是很奇怪。
答案 0 :(得分:4)
编译时是否知道键和值类型?如果是这样,你可以为漂亮的打印制作一个通用方法,让编译器为你推断出类型,如:
static void Main(string[] args)
{
var obj = new Dictionary<string, string>()
{
{ "foo", "bar" },
{ "baz", "ack" },
};
var stringVersion = GetStringVersion(obj);
Console.WriteLine(stringVersion);
}
private static string GetStringVersion<TKey, TValue>(Dictionary<TKey, TValue> dict)
{
return "{" + string.Join(Environment.NewLine, dict.Select(e => string.Format(" {0}: {1}", e.Key, e.Value))) + "}";
}
就你所看到的行为而言,由于反向竞争和设计决定,这是一个众所周知的奇怪案例:
http://blogs.msdn.com/b/bclteam/archive/2004/09/03/225473.aspx
我们讨论了IEnumerable实现的问题 字典。 IEnumerable.GetEnumerator()。当前应该是什么类型 返回? KeyValuePair还是DictionaryEntry?同样的 ICollection.CopyTo。应该将哪种类型的实例复制到 阵列?
我们决定了以下内容:
IEnumerable
和ICollection
接口实施将使用KeyValuePair<K,V>
作为项目类型。IDictionary
具体成员(GetEnumerator
返回IDictionaryEnumerator
)将使用DictionaryEntry
作为项目类型。 < / LI> 醇>原因是我们正在
IEnumerator<T>
扩展IEnumerator
的过程中进行更改。从Dictionary<K,V>
- &gt;IEnumerable<T>
- &gt;IEnumerable
走过层次结构会非常奇怪,我们突然改变了枚举器返回的项目类型。
由于该设计决定(在创建.NET 2.0期间),当您对非通用IEnumerable进行操作时,GetEnumerator()调用返回IDictionaryEnumerator,结果项的类型为DictionaryEntry(可能用于反向compat)使用Hashtable类型迭代)。但是,一旦调用了通用的IEnumerable(一旦你执行Cast()或OfType()就会发生这种情况,你将获得KeyValuePair项目。
请注意,在非泛型上下文中使用Dictionary是一个特别奇怪的事情--Hashtable(仍然)迭代为DictionaryEntry项目就好了,并且在Dictionary上的'normal'迭代为你提供了KeyValuePair项。
正如其他人所说,如果可以的话,你应该坚持使用通用访问,因为它会让你在Dictionary的设计决策中避免这个小小的“陷阱”。
答案 1 :(得分:1)
您正在尝试将IDictionary本身转换为DictionaryEntry。在foreach循环中,您不会转换IDictionary,而是包含其中的项目。
您可以执行此操作并使用列表:
var list = new List<DictionaryEntry>();
foreach (DictionaryEntry de in (IDictionary)obj)
list.Add(de);
return "{" + string.Join(Environment.NewLine, list.Select(e => string.Format(" {0}: {1}", PrettyString(e.Key), PrettyString(e.Value)))) + "}";
答案 2 :(得分:1)
我投票结束了这个问题,因为this answer已经足够了。
这是我的解决方案:
static class EnumerableExt
{
public static IEnumerable<DictionaryEntry> Entries(this IDictionary dict)
{
foreach (var item in dict) yield return (DictionaryEntry)item;
}
}
请注意
return dict.Cast<DictionaryEntry>();
不在这里工作,尽管Resharper告诉你。