在LINQ查询中将KeyValuePair转换为匿名类型

7
我有一个IEnumerable<KeyValuePair<string,string>>,希望得到一个匿名对象,其中键作为属性名,值作为属性值。我尝试了各种选择表达式(甚至没有编译...)和使用ExpandoObject的方法(见下文),但都没有成功。有没有好的方法可以做到这一点?如果可能的话,我想避免额外的显式迭代集合(即用某种LINQ语句完成所有操作)。以下是我目前尝试过的方法,希望它也能澄清我的意图:
var kvps = getProps(); // returns IEnumerable<KeyValuePair<string,string>>

dynamic o = new ExpandoObject();
foreach (var kvp in kvps)
{
    o.Add(kvp);
}

这在编译时没问题,但运行时出现一个YSOD,并显示“System.Dynamic.ExpandoObject”不包含“Add”的定义——我猜它在编译时工作是因为o是动态的,所以编译器不知道是否已经添加了.Add()方法。奇怪的是,在ExpandoObject的MSDN文档页面上,.Add()被列为几个“显式实现接口方法”之一。

对我来说,将其转换为动态对象并不是必要的——我只需要得到一个属性名称和值根据键值对的键和值。

更新: 好吧,这有点尴尬。事实证明这也是一个XY问题。

我正在尝试使用ASP.NET MVC的内置功能将其呈现为JSON,只需在控制器中返回Json(data)即可。所有答案都很好地完成了我最初的要求,但当我将此对象作为data传递时,我仍然没有得到我想要的结果:
// What I get:
[
   { Key: 'firstkey', Value: 'FirstValue' }, 
   { Key: 'secondKey', Value: 'secondValue' } 
]

// What I want:
{ firstKey: 'FirstValue', secondKey: 'secondValue' }

显然,添加了相关属性的ExpandoObject并不能满足需求 - 在呈现之前被转换为字典...

1
是的,我已经看过了这个问题。那确实是一个XY问题,没有帮助到我解决我的问题。 - Tomas Aschan
3个回答

7
您需要在填充时将ExpandoObject作为IDictionary<string,object>使用:
var kvps = getProps(); // returns IEnumerable<KeyValuePair<string,string>>

IDictionary<string, object> o = new ExpandoObject();
foreach (var kvp in kvps)
{
    // Or use Add(kvp.Key, kvp.Value), if you want
    o[kvp.Key] = kvp.Value;
}

dynamic d = o;
// Now you can use the properties

这在第一行就给我编译错误 (IDictionary<object, object> o = new ExpandoObject();),但既然是你让我这么做,我就觉得编译器错了。我猜它认为应该是 IDictionary<string,object> - 我会立即告诉它按你说的方式去做。 - Tomas Aschan
@TomasLycken:已经编辑了我的帖子,将object更改为string,谢谢。其余部分似乎取决于JSON转换器。您可能会发现另一个JSON序列化框架(例如JSON.NET)可以解决这个问题。 - Jon Skeet

6

ExpandoObject 明确实现了 IDictionary<string, object> - 因此您需要先将其转换为该类型:

var kvps = getProps();
dynamic o = new ExpandoObject();
var dict = o as IDictionary<string, object>;
foreach (var kvp in kvps)
{
    dict.Add(kvp.Key, kvp.Value);
}

现在您可以像预期的那样使用o
var example = o.YourKey;

我将使用ASP.NET MVC的内置功能,通过在我的控制器中简单地返回Json(data)来将其呈现为JSON。
要做到这一点,您需要序列化一个字典,而不是ExpandoObject。MVC 3的JSON序列化程序已经使用字典完成了这个任务。您所要做的就是将您的IEnumerable<KeyValuePair<string, object>>转换成字典:
var kvps = getProps();
var dictionary = kvps.ToDictionary(k => k.Key, v => v.Value);
return Json(dictionary, JsonRequestBehavior.AllowGet); //take out allow get if you don't need it.

无需动态。

谢谢!不过,我有点太快地阐述了我的问题 - 请看我的更新... - Tomas Aschan
@TomasLycken 我在更新的代码中遇到了一个小问题,我使用了 ToDictionary(k => k.Value, v => v.Value); 而不是 ToDictionary(k => k.Key, v => v.Value); - vcsjones
实际上,它对我来说运行得很好。为了清晰起见,我将其更改为 ToDictionary(kvp => kvp.Key, kvp => kvp.Value),然后它正好做到了我想要的 =) - Tomas Aschan

1

我认为你需要将你的扩展对象转换为IDictionary并调用Add(string, object)方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接