ChatGPT解决这个技术问题 Extra ChatGPT

A generic list of anonymous class

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});
    ....
}
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" }}
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 it

J
Jon Skeet

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 :)


@DHornpout: That would give an array, not a List.
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?)
@DHornpout: Do you have "using System.Linq;" at the top of your file? ToList is a LINQ operator.
Got it.. Need to include "using System.Linq". Thanks.
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).
P
Paul Bellora

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);

Dutt, your code should work without the .ToList() at the end.
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();
@towpse any solution about it ?
@Dutt, any sample if I use a method (function) that returns a List ?
Now there are method string.Join and string interpolation, so no need to use foreach and Format.
P
Paul Rouleau

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();   

Thanks for the idea. A suggestion, you can avoid allocating a dummy list if you use Enumerable.Empty<object>().Select(o=>definition).ToList()
Nice one! This should be the accepted answer
M
Micha Wiedenmann

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.


It's not strongly-typed, though, in the sense that you'll have no compiler intellisense support for the items in the list.
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.
But in those cases the source type is dynamic after all, it makes no sense to use a List for anonymous types.
Very helpful. Especially if the list has to be defined before anonymous items are added into it.
B
Bassem

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"));

R
Rostov

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.


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.
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).
L
Luis Perez

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 });
}

Yes this solution will help solve initialize the Anonymous array. Thanks.
Just put a little after the method name.
M
MalachiteBR

You can do this in your code.

var list = new[] { new { Id = 1, Name = "Foo" } }.ToList();
list.Add(new { Id = 2, Name = "Bar" });

D
Damith Asanka

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);
        }
    }

M
MEC

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();

Any reason to reject my edit? Following answer returns IEnumerable, whereas my version returns List, exactly what OP has asked.
I prefer this approach, or even one closer to this answer: new object[] { }.Select(o => new { Id = default(int), Name = default(string) }).ToList()
C
Code Name Jack

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.


u
user_v

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.


B
Brackus

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();

Using a string as a array initializer may work but is very bad practice
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?
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 inefficient
T
Tom Dee

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.


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.
P
Paul Bellora

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();
        }
    }
}

J
Jon Skeet

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.


m
morlock
var list = new[]{
new{
FirstField = default(string),
SecondField = default(int),
ThirdField = default(double)
}
}.ToList();
list.RemoveAt(0);

C
Community

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://stackoverflow.com/a/27455822/4536527.

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.


n
nawfal

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();

B
BrainStorm.exe

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.


M
Matteo Gariglio

Try with this:

var result = new List<object>();

foreach (var test in model.ToList()) {
   result.Add(new {Id = test.IdSoc,Nom = test.Nom});
}

Where is the list of anonymous type?