如何转换List<;词典<;字符串,对象>>;进入列表<;[具有动态属性的新类]>;
本文关键字:lt gt 列表 新类 属性 动态 转换 何转换 List 字符串 词典 | 更新日期: 2023-09-27 18:24:14
我有一个设计,其中类持有List<>Summary对象,每个Summary都是半动态属性的字典。也就是说,给定列表中的每个Summary在字典中都具有相同的键。我使用这种设计来构建一组动态"属性"来跟踪摘要值,因为根据我的项目规范,这些摘要值将在运行时进行配置。
问题是:如何将此列表展开,以便将列表中的每个项视为字典中的键是实际属性
我尝试过将Dictionary转换为列表的不同变体,但这似乎本质上是错误的,因为我真的需要将键视为属性。我想我需要使用C#4.0+的新动态特性和ExpandoObject,但我不能完全正确。
下面的代码显示了基本设置,"flattenedSummary"提供了我想要的东西——一个动态类型的新列表,其属性是Summary字典的键。然而,这是有缺陷的,因为我已经对属性名称进行了硬编码,但我不能这样做,因为我要到运行时才能真正了解它们。
flattenedSummary2版本试图使列表变平,但由于返回的类型仍然是list,而不是我想要的list,因此没有达到要求。
public class Summary : Dictionary<string, object>
{
}
public class ClassA
{
public List<Summary> Summaries = new List<Summary>();
}
static void Main(string[] args)
{
ClassA a = new ClassA();
var summary = new Summary();
summary.Add("Year", 2010);
summary.Add("Income", 1000m);
summary.Add("Expenses", 500m);
a.Summaries.Add(summary);
summary = new Summary();
summary.Add("Year", 2011);
summary.Add("Income", 2000m);
summary.Add("Expenses", 700m);
a.Summaries.Add(summary);
summary = new Summary();
summary.Add("Year", 2012);
summary.Add("Income", 1000m);
summary.Add("Expenses", 800m);
a.Summaries.Add(summary);
var flattenedSummary = from s in a.Summaries select new { Year = s["Year"], Income = s["Income"], Expenses = s["Expenses"] };
ObjectDumper.Write(flattenedSummary, 1);
var flattenedSummary2 = Convert(a);
ObjectDumper.Write(flattenedSummary2, 1);
Console.ReadKey();
}
public static List<ExpandoObject> Convert(ClassA a)
{
var list = new List<ExpandoObject>();
foreach (Summary summary in a.Summaries)
{
IDictionary<string, object> fields = new ExpandoObject();
foreach (var field in summary)
{
fields.Add(field.Key.ToString(), field.Value);
}
dynamic s = fields;
list.Add(s);
}
return list;
}
Daniel,
我发现这篇文章有一个可能对你有用的解决方案。http://theburningmonk.com/2011/05/idictionarystring-object-to-expandoobject-extension-method/
所以你应该创建扩展方法。。。
public static ExpandoObject ToExpando(this IDictionary<string, object> dictionary)
{
var expando = new ExpandoObject();
var expandoDic = (IDictionary<string, object>)expando;
// go through the items in the dictionary and copy over the key value pairs)
foreach (var kvp in dictionary)
{
// if the value can also be turned into an ExpandoObject, then do it!
if (kvp.Value is IDictionary<string, object>)
{
var expandoValue = ((IDictionary<string, object>)kvp.Value).ToExpando();
expandoDic.Add(kvp.Key, expandoValue);
}
else if (kvp.Value is ICollection)
{
// iterate through the collection and convert any strin-object dictionaries
// along the way into expando objects
var itemList = new List<object>();
foreach (var item in (ICollection)kvp.Value)
{
if (item is IDictionary<string, object>)
{
var expandoItem = ((IDictionary<string, object>)item).ToExpando();
itemList.Add(expandoItem);
}
else
{
itemList.Add(item);
}
}
expandoDic.Add(kvp.Key, itemList);
}
else
{
expandoDic.Add(kvp);
}
}
return expando;
}
然后从你的主功能。。。
List<ExpandoObject> flattenSummary3 = new List<ExpandoObject>();
foreach ( var s in a.Summaries)
{
flattenSummary3.Add(s.ToExpando());
}
现在,flattenSummary3变量将包含一个可以通过属性引用的ExpandObjects列表。
我希望这能有所帮助。
虽然我接受了Ed的答案,因为它非常接近,但我提供了以下代码,以防其他人发现它有用。关键的变化是确保ExpandoObject的所有使用都设置为动态的,以便最终的List是动态的。如果没有这些更改,检查列表中的类型仍然返回ExpandoObject(例如,json序列化给出的是ExpandoObject,而不是预期的属性名称/值)。
首先,ToExpando()方法(可能应该称为ToDynamic):
public static dynamic ToExpando(this IDictionary<string, object> dictionary)
{
dynamic expando = new ExpandoObject();
var expandoDic = (IDictionary<string, object>)expando;
// go through the items in the dictionary and copy over the key value pairs)
foreach (var kvp in dictionary)
{
// if the value can also be turned into an ExpandoObject, then do it!
if (kvp.Value is IDictionary<string, object>)
{
var expandoValue = ((IDictionary<string, object>)kvp.Value).ToExpando();
expandoDic.Add(kvp.Key, expandoValue);
}
else if (kvp.Value is ICollection)
{
// iterate through the collection and convert any strin-object dictionaries
// along the way into expando objects
var itemList = new List<object>();
foreach (var item in (ICollection)kvp.Value)
{
if (item is IDictionary<string, object>)
{
var expandoItem = ((IDictionary<string, object>)item).ToExpando();
itemList.Add(expandoItem);
}
else
{
itemList.Add(item);
}
}
expandoDic.Add(kvp.Key, itemList);
}
else
{
expandoDic.Add(kvp);
}
}
return expando;
}
调用代码如下所示:
List<dynamic> summaries = new List<dynamic>();
foreach (var s in a.Summaries)
{
summaries.Add(s.DynamicFields.ToExpando());
}
或者更紧凑的版本:
a.Summaries.Select(s => s.DynamicFields.ToExpando())
以上所有内容都提供了一个可以参考的对象:
int year = a.Summaries[0].Year; // Year is a dynamic property of type int
decimal income = a.Summaries[0].Income; // Income is a dynamic property of type decimal
当然,我不知道这些属性,但它们可以序列化为json,或者,经过一些调整,可以用于绑定网格或其他UI元素以进行显示。