Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cast List<object> to AnonymousTypes list

Tags:

c#

asp.net

I have populated the follow list with objects of type AnonymousType

List<object> someList = new List<object>();

someList.Add(new { foo = 1 });

My problem is that I can't make it stronly typed to do something like this:

someList.Where(x=> x.foo == 1);

However, it's possible on this list:

var someList = new[] { new { foo = 1 } };

Can I cast my first list to make it behave like the second list? I want to be able to use lambda expressions on the properties like I showed above.

like image 876
Johan Avatar asked Jul 05 '13 12:07

Johan


People also ask

How do I make an anonymous object?

You create anonymous types by using the new operator together with an object initializer. For more information about object initializers, see Object and Collection Initializers. The following example shows an anonymous type that is initialized with two properties named Amount and Message .

How to specify anonymous type C#?

You create an anonymous type using the new operator with an object initializer syntax. The implicitly typed variable- var is used to hold the reference of anonymous types.

What is object anonymous?

An anonymous object is basically a value that has been created but has no name. Since they have no name, there's no other way to refer to them beyond the point where they are created. Consequently, they have “expression scope,” meaning they are created, evaluated, and destroyed everything within a single expression.

When you define an anonymous type the compiler converts the type into?

Anonymous types are class type, directly derived from “System. Object” so they are reference types. If two or more Anonymous types have same properties in same order in a same assembly then compiler treats them as same type. All properties of anonymous types are read only.


2 Answers

You can take advantage of generics and type inference to create the list for you:

public static List<T> CreateAnonymousList<T>(params T[] entries)
{
    return new List<T>(entries);
}

Usage like:

var someList = CreateAnonymousList(new { foo = 1 }, new { foo = 2 }, new { foo = 1 });

someList.Where(x => x.foo == 1);

Naturally you won't be able to do much with it. You'll never be able to strongly type it in your code to anything other than var or return it out from your method or anything you normally wouldn't be able to do with anonymous types. If you want to do more, you'll just have to bite the (small) bullet and define a class for your anonymous type.


Rereading your question, you can still perform LINQ queries on an array:

var someArray = new[]{new { foo = 1 }, new { foo = 2 }, new { foo = 1 }};
someArray.Where(x => x.foo == 1)

So unless you are modifying it (say via standard List<T> operations like Add or Remove) then there's no reason to have to convert it to a List<T>.

I realize that maybe you want to still be able to pass it back (for some reason) and still do operations on it without knowing its anonymous type. In that case you could treat it as dynamic and perform the operations at runtime, but you lose any intellisense/strong typing that you'd normally have with the anonymous type:

List<dynamic> someDynamicList = new List<dynamic>() {new { foo = 1 }, new { foo = 2 }, new { foo = 1 }};
someDynamicList.Where(x => x.foo == 1)

One last method as pointed out by Tim Schmelter leveraging Jon Skeet's CastByExample, but extended to convert your collection with an extension method:

public static IEnumerable<T> CastByExample<T>(this IEnumerable source, T example)
{
    foreach(object entry in source)
        yield return (T)entry;
}

public static IEnumerable CreateAnonymousData()
{
    return new[]{new { foo = 1 }, new { foo = 2 }, new { foo = 1 }};
}

With usage like:

var anonymousData = CreateAnonymousData();
var typedAnonymousData = anonymousData.CastByExample(new { foo = 1 });
typedAnonymousData.Where(x => x.foo == 1);

This takes advantage of the fact that within the same assembly, anonymous types declared with the same parameter names, types, and order compile to the same type. This won't work if you need to call your CreateAnonymousData from outside the current assembly and you have to maintain the signature of your foo anonymous type everywhere you use it (add/change its signature, you must update it everywhere you use it or you're going to have a bad time).

But I think it's becoming more clear now that the best solution to this is to simply define a class representation of your anonymous type.

like image 197
Chris Sinclair Avatar answered Oct 08 '22 18:10

Chris Sinclair


You can use Jon Skeets' CastByExample:

public static T CastByExample<T>(object input, T example)
{
    return (T)input;
}

List<object> someList = new List<object>() { 
    new { foo = 1 },new { foo = 2 },new { foo = 3 }
};

var example = new { foo = 0 };

foreach (object obj in someList)
{
    var x = CastByExample(obj, example);
    Console.WriteLine("Foo: " + x.foo);
}
like image 39
Tim Schmelter Avatar answered Oct 08 '22 17:10

Tim Schmelter