27

I am calling a method that returns a List variable that contains a c# Anonymous Type objects. For example:

List<object> list = new List<object>();
foreach ( Contact c in allContacts ) {
    list.Add( new {
        ContactID = c.ContactID,
        FullName = c.FullName
    });
}
return list;

How do I reference this type properties in the code I am working on like for example

foreach ( object o in list ) {
    Console.WriteLine( o.ContactID );
}

I know that my sample is not possible, I have only wrote that way to say that I need to identify each property of the anonymous type exactly.

Thanks!

Solution:

Not just one of the answer is correct and/or suggest a working solution. I have ended up to using Option 3 of Greg answer. And I learned something very interesting regarding the dynamic in .NET 4.0!

Lorenzo
  • 29,081
  • 49
  • 125
  • 222
  • possible duplicate of [Accessing C# Anonymous Type Objects](http://stackoverflow.com/questions/713521/accessing-c-sharp-anonymous-type-objects) – nawfal Jun 28 '14 at 07:52

8 Answers8

36

You can't return a list of an anonymous type, it will have to be a list of object. Thus you will lose the type information.

Option 1
Don't use an anonymous type. If you are trying to use an anonymous type in more than one method, then create a real class.

Option 2
Don't downcast your anonymous type to object. (must be in one method)

var list = allContacts
             .Select(c => new { c.ContactID, c.FullName })
             .ToList();

foreach (var o in list) {
    Console.WriteLine(o.ContactID);
}

Option 3
Use the dynamic keyword. (.NET 4 required)

foreach (dynamic o in list) {
    Console.WriteLine(o.ContactID);
}

Option 4
Use some dirty reflection.

Greg
  • 23,155
  • 11
  • 57
  • 79
  • 1
    Option 5. Return a List of two-item Tuples (ex: `List>`). (but go for option 1.) – Anthony Pegram Oct 14 '10 at 17:29
  • Option 3 say that I miss Dinamic runtime binder. What is that? Should I import something? – Lorenzo Oct 14 '10 at 17:32
  • 3
    +1 Option 1 is really the best to reuse the type in different methods. – Jordão Oct 14 '10 at 17:43
  • Option 3 is unnecessary, really, when you can just use a custom class that is non-anonymous (nonymous?). It adds unnecessary overhead and doesn't buy you anything except fewer keystrokes. – siride Oct 16 '10 at 22:41
  • @Greg: does Option 3 works even if the returned List is inside a satellite DLL? – Lorenzo Oct 18 '10 at 15:44
  • @Lorenzo, yes it would work regardless of where the list comes from. When you use the `dynamic` type, the call to `o.ContactID` will be resolved using the actual type of `o` at runtime. But be advised that `dynamic` is intended for interoperability with dynamic libraries, and - while it would work to use in your situation - you should really use option 1 if you can. Your code would be more maintainable. – Greg Oct 18 '10 at 15:57
  • @Greg & @Lorenzo actually it would not work from a satellite dll unless it was a friend assembly. Anonymous types are internal, thus the dlr would throw a Runtime Binding Exception because it wouldn't be to bind due to permissions. – jbtule Mar 08 '11 at 16:06
4
foreach ( var o in list ) {
    Console.WriteLine( o.ContactID );
}

this will work only if list is IEnumerable<anonymous type>, like this:

var list = allContacts.Select(c => new {
        ContactID = c.ContactID,
        FullName = c.FullName
    });
}

but you can't return anonymous types, because you must define return type (you can't return var) and anonymous types can't have names. you should create non-anonymous type if you with to pass it. Actually anonymous types should not be used too much, except for inside of queries.

Andrey
  • 59,039
  • 12
  • 119
  • 163
  • 1
    You can't return `IEnumerable` – Greg Oct 14 '10 at 17:23
  • The return give me a warning that cannot do an implicit conversione between IEnumerable and List. How do I have to change my method signature? – Lorenzo Oct 14 '10 at 17:24
  • 1
    @Lorenzo as it was mentioned, you can't return anonymous types, because you must define return type and anonymous types can't have names. you should create non-anonymous type if you with to pass it. Actually anonymous types should not be used too much, except for inside of queries. – Andrey Oct 14 '10 at 17:41
  • thnaks for helping. Sorry for ignorance but was my first time using Anonymous types. These answers have been very useful to me! – Lorenzo Oct 14 '10 at 17:56
2

If you have a method like this:

  List<object> GetContactInfo() {
    List<object> list = new List<object>();
    foreach ( Contact c in allContacts ) { 
        list.Add( new { 
            ContactID = c.ContactID, 
            FullName = c.FullName 
        }); 
    } 
    return list;
  }

You shouldn't really do this, but there's a very ugly and not future-proof technique that you can use:

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

  // .....

  var example = new { ContactID = 0, FullName = "" };
  foreach (var o in GetContactInfo()) {
    var c = CastByExample(o, example);
    Console.WriteLine(c.ContactID);
  }

It relies on the fact (which can change!) that the compiler reuses anonymous types for types that have the same "shape" (properties names and types). Since your "example" matches the "shape" of the type in the method, the same type is reused.

Dynamic variables in C# 4 are the best way to solve this though.

Jordão
  • 55,340
  • 13
  • 112
  • 144
1

You cannot do this with anonymous types. Just create a Contact class/struct and use that.

List<object> list = new List<object>();
foreach ( Contact c in allContacts ) {
    list.Add( c );
}

Then you can do this:

foreach ( var o in list ) {
    Console.WriteLine( o.ContactID );
}

...or this:

foreach ( object o in list ) {
    Console.WriteLine( ((Contact)o).ContactID ); //Gives intellisense
}

Of course you should in that case just do create a Contact list instead of an object list:

List<Contact> list = new List<Contact>();
foreach ( Contact c in allContacts ) {
    list.Add( c );
}

EDIT: Missed essential part of the question. Now fixed.
EDIT: Changed answer yet again. See above.

Mike Webb
  • 8,855
  • 18
  • 78
  • 111
  • o is not of type Contact, it's an anonymous type. – Paul Ruane Oct 14 '10 at 17:19
  • this is wrong. o is not instance of `Contact`, but instance of anonymous type – Andrey Oct 14 '10 at 17:19
  • Oh, missed that part. Read it too fast. The others are correct. Use 'var'. – Mike Webb Oct 14 '10 at 17:21
  • 2
    Won't work. `list`'s type is `List`. Thus `var o` is equivalent to `Object o`. `Object` does not have a property `ContactID`, therefore it would fail to compile. – Greg Oct 14 '10 at 17:40
  • I guess I need to look more into anonymous types. Fixed yet again. – Mike Webb Oct 15 '10 at 18:03
  • @Mike - It still doesn't work. The list doesn't contain instances of `Contact`, it contains instances of an anonymous type. You can't cast them to `Contact`. – Greg Oct 15 '10 at 18:05
  • @Greg - You can if you define and use a Contact class/struct instead of an anonymous type as I have said above. – Mike Webb Oct 15 '10 at 18:13
  • @Mike - Yep, it would work to define another class. `Contact` is the name of the original class so a different name should be used for this new class. – Greg Oct 15 '10 at 18:17
  • @Greg - I wasn't being specific enough. I added the code to better explain what I was thinking. – Mike Webb Oct 15 '10 at 18:17
0

I know I'm late to the party but I researching somthing else and found this article which answers your question.

It is possible to cast the list of objects back into the anonymous type.

    public static void Main()
    {
        foreach (object item in GetList())
        {
            var x = Cast(item, new { ContactID = 0, FullName = "" });
            Console.WriteLine(x.ContactID + " " + x.FullName);
        }

    }

    public static IEnumerable<object> GetList()
    {
        yield return new { ContactID = 4, FullName = "Jack Smith" };
        yield return new { ContactID = 5, FullName = "John Doe" };
    }

    public static T Cast<T>(object obj, T type)
    {
        return (T)obj;
    }
mashrur
  • 445
  • 4
  • 13
0

list back

public static void Main()
{
    foreach (object item in GetList())
    {
        var x = Cast(item, new { ContactID = 0, FullName = "" });
        Console.WriteLine(x.ContactID + " " + x.FullName);
    }

}

public static IEnumerable<object> GetList()
{
    yield return new { ContactID = 4, FullName = "Jack Smith" };
    yield return new { ContactID = 5, FullName = "John Doe" };
}

public static T Cast<T>(object obj, T type)
{
    return (T)obj;
}
0

replacing object with var in for each construct may work

TalentTuner
  • 17,262
  • 5
  • 38
  • 63
-1

i would use

allContacts
 .Select(c => new { c.ContactID, c.FullName })
 .ToList()
 .ForEach(c => {
   ...do stuff;
 });

then you dont need to declare at all. i believe that less declaration, less semi-colon leads to less bug

Lorenzo
  • 29,081
  • 49
  • 125
  • 222
Bonshington
  • 3,970
  • 2
  • 25
  • 20