将匿名类型的List 转换为Dictionary <string,SortedList >

我有一个函数创建一个本地List ,其中对象是一个匿名类型。 我需要在Dictionary<string, SortedList>返回这些结果。

数据列表如下所示。

 { Security = "6752 JT", Date = {1/17/2011 12:00:00 AM}, zScore = 1 } { Security = "6753 JT", Date = {1/17/2011 12:00:00 AM}, zScore = 2 } { Security = "6754 JT", Date = {1/17/2011 12:00:00 AM}, zScore = 3 } { Security = "6752 JT", Date = {1/18/2011 12:00:00 AM}, zScore = 1 } { Security = "6753 JT", Date = {1/18/2011 12:00:00 AM}, zScore = 2 } { Security = "6754 JT", Date = {1/18/2011 12:00:00 AM}, zScore = 3 } { Security = "6752 JT", Date = {1/19/2011 12:00:00 AM}, zScore = 1 } { Security = "6753 JT", Date = {1/19/2011 12:00:00 AM}, zScore = 2 } { Security = "6754 JT", Date = {1/19/2011 12:00:00 AM}, zScore = 3 } 

我想使用LINQ将这些结果放入Dictionary<string, SortedList> ,其中字典的键是Security,值是包含安全性的所有日期/ z分数值的SortedList。

当LINQ是自定义对象时,我可以在LINQ中执行此操作,但是如何使用匿名类型对象执行此操作?

注意:此查询最初是以不必要的复杂且措辞不当的方式发布的。 这可能是没有人回答的原因! 我要包含链接,以防你想知道为什么输出是这种forms。
C#LINQ Z-Score查询输出到Dictionary <string,SortedList >

所以基本上你问的是如何从object取消匿名类型?

首先,我建议不要使用List而只是…创建自定义类。

 public class SecurityScore { public string Security { get; set; } public DateTime Date { get; set; } public int ZScore { get; set; } } 

但是,如果出于任何原因需要这样做,请尝试Jon Skeet的这种方法:

我一直都知道通过声明该方法将返回对象来返回匿名类型的实例非常容易。 但是,在我今天之前没有想到你之后可以实际回到那种类型。 当然,您不能只使用普通的强制转换表达式 – 这需要在编译时知道类型的名称。 但是你可以在generics方法中进行转换…并且你可以使用类型推断来提供类型参数……如果顺序,名称和类型,两个匿名类型实例创建表达式将在同一个程序集中使用相同的类型属性是一样的。

如果您想探索他的解决方案,请查看他关于该主题的博客文章 。

为了完整起见,我将在此处发布他的代码:

 static class GrottyHacks { internal static T Cast(object target, T example) { return (T) target; } } class CheesecakeFactory { static object CreateCheesecake() { return new { Fruit="Strawberry", Topping="Chocolate" }; } static void Main() { object weaklyTyped = CreateCheesecake(); var stronglyTyped = GrottyHacks.Cast(weaklyTyped, new { Fruit="", Topping="" }); Console.WriteLine("Cheesecake: {0} ({1})", stronglyTyped.Fruit, stronglyTyped.Topping); } } 

我必须承认,虽然我不喜欢装箱/取消装箱匿名类型的想法,但他的方法非常棒,占用了相对较少的代码。

所以,既然我已经给你一个可能的解决方案,我必须问 – 为什么你这样做,而不是创建一个简单的类?

编辑:同样为了完整性,我将使用Jon Skeet的解决方案实现您的特定问题:

 void Main() { // Create a list of (boxed) anonymous objects var securitiesBoxed = new List() { new { Security = "6752 JT", Date = DateTime.Parse("1/17/2011 12:00:00 AM"), zScore = 1 }, new { Security = "6753 JT", Date = DateTime.Parse("1/17/2011 12:00:00 AM"), zScore = 2 }, new { Security = "6754 JT", Date = DateTime.Parse("1/17/2011 12:00:00 AM"), zScore = 3 }, new { Security = "6752 JT", Date = DateTime.Parse("1/18/2011 12:00:00 AM"), zScore = 1 }, new { Security = "6753 JT", Date = DateTime.Parse("1/18/2011 12:00:00 AM"), zScore = 2 }, new { Security = "6754 JT", Date = DateTime.Parse("1/18/2011 12:00:00 AM"), zScore = 3 }, new { Security = "6752 JT", Date = DateTime.Parse("1/19/2011 12:00:00 AM"), zScore = 1 }, new { Security = "6753 JT", Date = DateTime.Parse("1/19/2011 12:00:00 AM"), zScore = 2 }, new { Security = "6754 JT", Date = DateTime.Parse("1/19/2011 12:00:00 AM"), zScore = 3 } }; // Now, to convert to a Dictionary>... var securitiesUnboxed = securitiesBoxed.Select(x => Cast(x, new { Security = "", Date = new DateTime(), zScore = 0 })) .GroupBy(x => x.Security) .ToDictionary(x => x.Key, x => x.OrderBy(y => y.Date)); } // This is the static method that will cast our anonymous type internal static T Cast(object target, T example) { return (T) target; } 

在LINQPad中 ,上面的代码产生以下数据:

linqified数据

Pandincus在他的回答中给出了一个可能的解决方案。 如果您使用的是.NET 4.0,并且可以利用dynamic类型 ,则可以使用占用空间较小的另一种解决方案:

 // list is a List var query = list.Cast() .GroupBy(o => o.Security) .ToDictionary(o => o.Key, o => new SortedList(o.ToDictionary(x => (DateTime)x.Date, x => (double)x.zScore))); foreach (var item in query) { Console.WriteLine("Security: " + item.Key); foreach (var kvp in item.Value) Console.WriteLine("Date: {0}, zScore: {1}", kvp.Key, kvp.Value); } 

这仍然感觉很乱,理想情况下,因为你正在产生结果,你应该通过重新思考你的方法避免这种混乱,并避免将项目添加到List 。 在您回答原始问题时 , 您似乎已经做到了这一点!

这没有经过测试。

  Dictionary> dict = yourList.ToDictionary(kv => kv.Security , kv => new KeyValuePair(kv.Date, kv.zScore)); 

根据以下评论进行编辑 ,您可以尝试List< SomeType >而不是List< object >

 class SomeType { public string Security {get;set;} public DateTime Date {get;set;} public int zScore {get;set;} } var results = new List(); results.Add(new { Security = secRank.Symbol, Date = sec.First().Date, zScore = zScore });