score:8

Accepted answer

So basically you're asking how to unbox an anonymous type from object?

First of all, I recommend not using a List<object> and just ... creating a custom class.

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

However, if for whatever reason you need to do this, try this approach from Jon Skeet:

I've always known that it's perfectly easy to return an instance of an anonymous type by declaring that the method will return object. However, it hadn't occurred to me before today that you can actually cast back to that type afterwards. Of course, you can't just use a normal cast expression - that requires the name of the type to be known at compile-time. But you can do a cast in a generic method... and you can use type inference to supply a type argument... and two anonymous type instance creation expressions will use the same type within the same assembly if the order, names and types of the properties are the same.

If you want to explore his solution, check out his blog post on the subject.

For completeness, I will post his code here:

static class GrottyHacks
{
    internal static T Cast<T>(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);            
    }
}

I must admit that, while I don't really like the idea of boxing/unboxing an anonymous type, his approach is pretty awesome, and takes up relatively few lines of code.

So, now that I've given you a possible solution, I must ask -- why are you doing it this way, as opposed to creating a simple class?

Edit: Also for completeness, here's how I would implement your particular problem using Jon Skeet's solution:

void Main()
{
    // Create a list of (boxed) anonymous objects
    var securitiesBoxed = new List<object>() {
        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<string, SortedList<DateTime, double>>...
    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<T>(object target, T example)
{
    return (T) target;
}

In LINQPad, the above code results in the following data:

linqified data

score:2

This is not tested.

 Dictionary<string, SortedList<DateTime, double>> dict = yourList.ToDictionary(kv => kv.Security , kv => new KeyValuePair(kv.Date, kv.zScore));

Edit based on comments below, you could try List< SomeType > instead of List< object >

class SomeType
{
    public string Security {get;set;}
    public DateTime Date {get;set;}
    public int zScore {get;set;}
}

var results = new List<SomeType>(); 
results.Add(new { Security = secRank.Symbol, Date = sec.First().Date, zScore = zScore });

score:4

Pandincus gave one possible solution in his answer. Another solution with a smaller footprint is available to you if you're using .NET 4.0 and can take advantage of the dynamic type:

// list is a List<object>
var query = list.Cast<dynamic>()
                .GroupBy(o => o.Security)
                .ToDictionary(o => o.Key,
                    o => new SortedList<DateTime, double>(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);
}

This still feels hackish and ideally, since you're generating the result, you should avoid this mess by rethinking your approach and avoid adding the items to a List<object>. It looks like you have done just that in your answer to your original question!


Related Articles