A generic list of anonymous class
Asked Answered
W

22

484

In C# 3.0 you can create anonymous class with the following syntax

var o = new { Id = 1, Name = "Foo" };

Is there a way to add these anonymous class to a generic list?

Example:

var o = new { Id = 1, Name = "Foo" };
var o1 = new { Id = 2, Name = "Bar" };

List<var> list = new List<var>();
list.Add(o);
list.Add(o1);

Another Example:

List<var> list = new List<var>();

while (....)
{
    ....
    list.Add(new {Id = x, Name = y});
    ....
}
Warder answered 4/3, 2009 at 22:8 Comment(2)
Note that all the objects must be typed the same in the array. Rarely you may need to help with a cast, especially for nulls new[] { new{ Id = (int?)null, Name = "Foo" }, new { Id = (int?)1, Name = "Foo" }}Kinchinjunga
anonymous types are designed to be used as temporary storage, in most cases you would create them in LINQ select statement using Select(i=>new {i.ID,i.Name}); which would return a IEnumerable of the correct type if you redefine your while clause into a LINQ.Where statement you shouldn't ever need the list and if you did you can then just call ToList on itVaporize
P
493

You could do:

var list = new[] { o, o1 }.ToList();

There are lots of ways of skinning this cat, but basically they'll all use type inference somewhere - which means you've got to be calling a generic method (possibly as an extension method). Another example might be:

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

var list = CreateList(o, o1);

You get the idea :)

Pikestaff answered 4/3, 2009 at 22:12 Comment(8)
The correct syntax (at least in 3.5) is var list = new[] {o, o1};Warder
@DHornpout: That would give an array, not a List<T>.Pikestaff
What version are you using? This is the compiler error I got Error 1 'System.Array' does not contain a definition for 'ToList' and no extension method 'ToList' accepting a first argument of type 'System.Array' could be found (are you missing a using directive or an assembly reference?)Warder
@DHornpout: Do you have "using System.Linq;" at the top of your file? ToList is a LINQ operator.Pikestaff
Got it.. Need to include "using System.Linq". Thanks.Warder
It does seem an inconsistency in Visual Studio, that intellisense isn't more helpful in uncovering missing includes of assemblies with referenced extension methods (same as referenced types).Nixon
Why do I get "object does not have 'x' property"? I use this method to pass an anonymous list to my view in ASP.NET MVC and there, I get this error.Kithara
@SaeedNeamati: I can't possibly tell without seeing your code. Sounds like you should ask a new question.Pikestaff
L
128

Here is the answer.

string result = String.Empty;

var list = new[]
{ 
    new { Number = 10, Name = "Smith" },
    new { Number = 10, Name = "John" } 
}.ToList();

foreach (var item in list)
{
    result += String.Format("Name={0}, Number={1}\n", item.Name, item.Number);
}

MessageBox.Show(result);
Leesen answered 30/10, 2009 at 9:7 Comment(5)
Dutt, your code should work without the .ToList() at the end.Warder
okay cool, now we need an example of replacing the new {} lines with a select statement. var list = sourceList.Select( o => new { o.ModelId, o.PartNumber, o.Quantity }).ToList();Lemma
@towpse any solution about it ?Meras
@Dutt, any sample if I use a method (function) that returns a List<T> ?Meras
Now there are method string.Join and string interpolation, so no need to use foreach and Format.Krol
D
82

There are many ways to do this, but some of the responses here are creating a list that contains garbage elements, which requires you to clear the list.

If you are looking for an empty list of the generic type, use a Select against a List of Tuples to make the empty list. No elements will be instantiated.

Here's the one-liner to create an empty list:

 var emptyList = new List<Tuple<int, string>>()
          .Select(t => new { Id = t.Item1, Name = t.Item2 }).ToList();

Then you can add to it using your generic type:

 emptyList.Add(new { Id = 1, Name = "foo" });
 emptyList.Add(new { Id = 2, Name = "bar" });

As an alternative, you can do something like below to create the empty list (But, I prefer the first example because you can use it for a populated collection of Tuples as well) :

 var emptyList = new List<object>()
          .Select(t => new { Id = default(int), Name = default(string) }).ToList();   
Dulcet answered 26/11, 2014 at 17:21 Comment(1)
Thanks for the idea. A suggestion, you can avoid allocating a dummy list if you use Enumerable.Empty<object>().Select(o=>definition).ToList()Redivivus
M
56

Not exactly, but you can say List<object> and things will work. However, list[0].Id won't work.

This will work at runtime in C# 4.0 by having a List<dynamic>, that is you won't get IntelliSense.

Meta answered 4/3, 2009 at 22:10 Comment(4)
It's not strongly-typed, though, in the sense that you'll have no compiler intellisense support for the items in the list.Tiddlywinks
I didn't say it was a great idea, but that it was possible :-) There could be a need if storing objects from Ruby for example.Meta
But in those cases the source type is dynamic after all, it makes no sense to use a List<dynamic> for anonymous types.Homelike
Very helpful. Especially if the list has to be defined before anonymous items are added into it.Chancemedley
A
46

If you are using C# 7 or above, you can use tuple types instead of anonymous types.

var myList = new List<(int IntProp, string StrProp)>();
myList.Add((IntProp: 123, StrProp: "XYZ"));
Abattoir answered 31/10, 2019 at 4:57 Comment(0)
M
24

I guess

List<T> CreateEmptyGenericList<T>(T example) {
    return new List<T>();
}

void something() {
    var o = new { Id = 1, Name = "foo" };
    var emptyListOfAnonymousType = CreateEmptyGenericList(o);
}

will work.

You might also consider writing it like this:

void something() {
    var String = string.Emtpy;
    var Integer = int.MinValue;
    var emptyListOfAnonymousType = CreateEmptyGenericList(new { Id = Integer, Name = String });
}
Micamicaela answered 4/3, 2009 at 22:35 Comment(2)
Yes this solution will help solve initialize the Anonymous array. Thanks.Warder
Just put a little <T> after the method name.Krystinakrystle
S
24

I usually use the following; mainly because you then "start" with a list that's empty.

var list = Enumerable.Range(0, 0).Select(e => new { ID = 1, Name = ""}).ToList();
list.Add(new {ID = 753159, Name = "Lamont Cranston"} );
//etc.

Lately, I've been writing it like this instead:

var list = Enumerable.Repeat(new { ID = 1, Name = "" }, 0).ToList();
list.Add(new {ID = 753159, Name = "Lamont Cranston"} );

Using the repeat method would also allow you to do:

var myObj = new { ID = 1, Name = "John" };
var list = Enumerable.Repeat(myObj, 1).ToList();
list.Add(new { ID = 2, Name = "Liana" });

..which gives you the initial list with the first item already added.

Sheridansherie answered 16/5, 2014 at 15:0 Comment(2)
You don't need to start with an empty list - you can do Range(0,1) and make your first object in the select statement be.. the first object.Alibi
You don't need to start with an empty list -- in the case where you know what the first item is (as in the example) then you're right in your comment. Many times though I use this for parsing an intermediate file / data source and don't access the first true item until using it in a LINQ projection scenario (and thus don't need to account for skipping the first record).Sheridansherie
E
22

You can do this in your code.

var list = new[] { new { Id = 1, Name = "Foo" } }.ToList();
list.Add(new { Id = 2, Name = "Bar" });
Eulalie answered 13/12, 2012 at 11:30 Comment(0)
B
13

I checked the IL on several answers. This code efficiently provides an empty List:

    using System.Linq;
    …
    var list = new[]{new{Id = default(int), Name = default(string)}}.Skip(1).ToList();
Bullish answered 15/12, 2015 at 6:10 Comment(2)
Any reason to reject my edit? Following answer returns IEnumerable, whereas my version returns List, exactly what OP has asked.Aa
I prefer this approach, or even one closer to this answer: new object[] { }.Select(o => new { Id = default(int), Name = default(string) }).ToList()Shuttering
P
12

In latest version 4.0, can use dynamic like below

var list = new List<dynamic>();
        list.Add(new {
            Name = "Damith"
    });
        foreach(var item in list){
            Console.WriteLine(item.Name);
        }
    }
Presume answered 31/5, 2017 at 9:31 Comment(0)
P
10

You can create a list of dynamic.

List<dynamic> anons=new List<dynamic>();
foreach (Model model in models)
{
   var anon= new
   {
      Id = model.Id,
      Name=model.Name
   };
   anons.Add(anon);
}

"dynamic" gets initialized by the first value added.

Parulis answered 26/12, 2017 at 18:40 Comment(0)
R
8

Here is my attempt.

List<object> list = new List<object> { new { Id = 10, Name = "Testing1" }, new {Id =2, Name ="Testing2" }}; 

I came up with this when I wrote something similar for making a Anonymous List for a custom type.

Rudyrudyard answered 7/7, 2011 at 11:11 Comment(0)
J
8

Here is a another method of creating a List of anonymous types that allows you to start with an empty list, but still have access to IntelliSense.

var items = "".Select( t => new {Id = 1, Name = "foo"} ).ToList();

If you wanted to keep the first item, just put one letter in the string.

var items = "1".Select( t => new {Id = 1, Name = "foo"} ).ToList();
Juice answered 12/9, 2014 at 22:13 Comment(3)
Using a string as a array initializer may work but is very bad practiceVaporize
I would say that most of the above answers are not particularly "good" practice, but that was kind of a given due to the nature of the question. Anonymous types were not really designed to work this way. I am curious though why my method is "worse" than the others? Something I'm missing?Juice
you are right as the question is asking for something that itself bad practice there can't be a good practice answer, but because you are using a string to generate an array of chars and then converting that into an array of what ever the user wants, which are unrelated types not to mention generating superfluous boxing and unboxing which is inefficientVaporize
I
8

I'm very surprised nobody has suggested collection initializers. This way can only add objects when the list is created hence the name however it seems like the nicest way of doing it. No need to create an array then convert it to a list.

var list = new List<dynamic>() 
{ 
    new { Id = 1, Name = "Foo" }, 
    new { Id = 2, Name = "Bar" } 
};

You can always use object instead of dynamic but trying to keep it in a true generic way then dynamic makes more sense.

Importation answered 9/10, 2019 at 16:29 Comment(1)
dynamic and object are treated differently at runtime and compile time. If you try to call "list[0].Id" using dynamic you won't get compile errors. Using object is not possible. Object is the base class from which all classes are inherited, a predetermined "type". Dynamic, on the other hand, is an "undetermined type" before code execution.Bi
G
6

Instead of this:

var o = new { Id = 1, Name = "Foo" }; 
var o1 = new { Id = 2, Name = "Bar" }; 

List <var> list = new List<var>(); 
list.Add(o); 
list.Add(o1);

You could do this:

var o = new { Id = 1, Name = "Foo" }; 
var o1 = new { Id = 2, Name = "Bar" }; 

List<object> list = new List<object>(); 
list.Add(o); 
list.Add(o1);

However, you will get a compiletime error if you try to do something like this in another scope, although it works at runtime:

private List<object> GetList()
{ 
    List<object> list = new List<object>();
    var o = new { Id = 1, Name = "Foo" }; 
    var o1 = new { Id = 2, Name = "Bar" }; 
    list.Add(o); 
    list.Add(o1);
    return list;
}

private void WriteList()
{
    foreach (var item in GetList()) 
    { 
        Console.WriteLine("Name={0}{1}", item.Name, Environment.NewLine); 
    }
}

The problem is that only the members of Object are available at runtime, although intellisense will show the properties id and name.

In .net 4.0 a solution is to use the keyword dynamic istead of object in the code above.

Another solution is to use reflection to get the properties

using System;
using System.Collections.Generic;
using System.Reflection;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Program p = new Program();
            var anonymous = p.GetList(new[]{
                new { Id = 1, Name = "Foo" },       
                new { Id = 2, Name = "Bar" }
            });

            p.WriteList(anonymous);
        }

        private List<T> GetList<T>(params T[] elements)
        {
            var a = TypeGenerator(elements);
            return a;
        }

        public static List<T> TypeGenerator<T>(T[] at)
        {
            return new List<T>(at);
        }

        private void WriteList<T>(List<T> elements)
        {
            PropertyInfo[] pi = typeof(T).GetProperties();
            foreach (var el in elements)
            {
                foreach (var p in pi)
                {
                    Console.WriteLine("{0}", p.GetValue(el, null));
                }
            }
            Console.ReadLine();
        }
    }
}
Gentility answered 30/11, 2010 at 9:34 Comment(0)
M
5

You can do it this way:

var o = new { Id = 1, Name = "Foo" };
var o1 = new { Id = 2, Name = "Bar" };

var array = new[] { o, o1 };
var list = array.ToList();

list.Add(new { Id = 3, Name = "Yeah" });

It seems a little "hacky" to me, but it works - if you really need to have a list and can't just use the anonymous array.

Mcalister answered 4/3, 2009 at 22:42 Comment(0)
I
5

This is an old question, but I thought I'd put in my C# 6 answer. I often have to set up test data that is easily entered in-code as a list of tuples. With a couple of extension functions, it is possible to have this nice, compact format, without repeating the names on each entry.

var people= new List<Tuple<int, int, string>>() {
    {1, 11, "Adam"},
    {2, 22, "Bill"},
    {3, 33, "Carol"}
}.Select(t => new { Id = t.Item1, Age = t.Item2, Name = t.Item3 });

This gives an IEnumerable - if you want a list that you can add to then just add ToList().

The magic comes from custom extension Add methods for tuples, as described at https://mcmap.net/q/28461/-how-to-easily-initialize-a-list-of-tuples.

public static class TupleListExtensions    {
    public static void Add<T1, T2>(this IList<Tuple<T1, T2>> list,
            T1 item1, T2 item2)       {
        list.Add(Tuple.Create(item1, item2));
    }

    public static void Add<T1, T2, T3>(this IList<Tuple<T1, T2, T3>> list,
            T1 item1, T2 item2, T3 item3) {
        list.Add(Tuple.Create(item1, item2, item3));
    }

// and so on...

}

The only thing I don't like is that the types are separated from the names, but if you really don't want to make a new class then this approach will still let you have readable data.

Indulgence answered 27/1, 2016 at 11:46 Comment(0)
R
4
var list = new[]{
new{
FirstField = default(string),
SecondField = default(int),
ThirdField = default(double)
}
}.ToList();
list.RemoveAt(0);
Rugging answered 2/2, 2012 at 10:20 Comment(0)
S
4

For your second example, where you have to initialize a new List<T>, one idea is to create an anonymous list, and then clear it.

var list = new[] { o, o1 }.ToList();
list.Clear();

//and you can keep adding.
while (....)
{
    ....
    list.Add(new { Id = x, Name = y });
    ....
}

Or as an extension method, should be easier:

public static List<T> GetEmptyListOfThisType<T>(this T item)
{
    return new List<T>();
}

//so you can call:
var list = new { Id = 0, Name = "" }.GetEmptyListOfThisType();

Or probably even shorter,

var list = new int[0].Select(x => new { Id = 0, Name = "" }).Tolist();
Shaquitashara answered 17/10, 2013 at 7:17 Comment(0)
R
1

Deriving from this answer, I came up with two methods that could do the task:

    /// <summary>
    /// Create a list of the given anonymous class. <paramref name="definition"/> isn't called, it is only used
    /// for the needed type inference. This overload is for when you don't have an instance of the anon class
    /// and don't want to make one to make the list.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="definition"></param>
    /// <returns></returns>
#pragma warning disable RECS0154 // Parameter is never used
    public static List<T> CreateListOfAnonType<T>(Func<T> definition)
#pragma warning restore RECS0154 // Parameter is never used
    {
        return new List<T>();
    }
    /// <summary>
    /// Create a list of the given anonymous class. <paramref name="definition"/> isn't added to the list, it is
    /// only used for the needed type inference. This overload is for when you do have an instance of the anon
    /// class and don't want the compiler to waste time making a temp class to define the type.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="definition"></param>
    /// <returns></returns>
#pragma warning disable RECS0154 // Parameter is never used
    public static List<T> CreateListOfAnonType<T>(T definition)
#pragma warning restore RECS0154 // Parameter is never used
    {
        return new List<T>();
    }

You can use the methods like

var emptyList = CreateListOfAnonType(()=>new { Id = default(int), Name = default(string) });
//or
var existingAnonInstance = new { Id = 59, Name = "Joe" };
var otherEmptyList = CreateListOfAnonType(existingAnonInstance);

This answer has a similar idea, but I didn't see it until after I made those methods.

Redivivus answered 12/2, 2019 at 20:5 Comment(0)
S
0

Using Reflection

Microsoft documentation about this topic.

using System;
using System.Collections;
using System.Collections.Generic;

var anonObj = new { Id = 1, Name = "Foo" };
var anonType = anonObj.GetType();

var listType = typeof(List<>);

// We know that List<> have only one generic argument, so we do this:
var contructed = listType.MakeGenericType(anonType);

// Create instance
var instance = Activator.CreateInstance(contructed);

// Using it
var list = (IList)instance;
list.Add(anonObj);

For Dictionary<,> you need to pass 2 arguments
Ex.: dicType.MakeGenericType( type1, type2 )

And for generic types with constraints (where T : struct), we need to do more verifications. Check microsoft docs to learn how.

Shadoof answered 20/1, 2023 at 17:52 Comment(0)
E
-2

Try with this:

var result = new List<object>();

foreach (var test in model.ToList()) {
   result.Add(new {Id = test.IdSoc,Nom = test.Nom});
}
Escrow answered 24/6, 2014 at 11:23 Comment(1)
Where is the list of anonymous type?Anethole

© 2022 - 2024 — McMap. All rights reserved.