Общий список анонимного класса - PullRequest
380 голосов
/ 05 марта 2009

В C # 3.0 вы можете создать анонимный класс со следующим синтаксисом

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

Есть ли способ добавить эти анонимные классы в общий список?

Пример:

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

Другой пример:

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

while (....)
{
    ....
    list.Add(new {Id = x, Name = y});
    ....
}

Ответы [ 20 ]

6 голосов
/ 13 сентября 2014

Вот еще один метод создания списка анонимных типов, который позволяет начинать с пустого списка, но при этом иметь доступ к IntelliSense.

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

Если вы хотите сохранить первый элемент, просто вставьте одну строку в строку.

var items = "1".Select( t => new {Id = 1, Name = "foo"} ).ToList();
5 голосов
/ 02 февраля 2012
var list = new[]{
new{
FirstField = default(string),
SecondField = default(int),
ThirdField = default(double)
}
}.ToList();
list.RemoveAt(0);
5 голосов
/ 30 ноября 2010

Вместо этого:

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

Вы можете сделать это:

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

Однако вы получите ошибку времени компиляции, если попытаетесь сделать что-то подобное в другой области, хотя это работает во время выполнения:

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

Проблема в том, что во время выполнения доступны только члены Object, хотя intellisense покажет свойства id и name .

В .net 4.0 решение заключается в использовании ключевого слова dynamic вместо object в приведенном выше коде.

Другим решением является использование отражения для получения свойств

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();
        }
    }
}
4 голосов
/ 26 декабря 2017

Вы можете создать динамический список.

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

«динамический» инициализируется первым добавленным значением.

3 голосов
/ 05 марта 2009

Вы можете сделать это так:

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

Мне это кажется немного "хакерским", но это работает - если вам действительно нужен список и вы не можете просто использовать анонимный массив.

3 голосов
/ 27 января 2016

Это старый вопрос, но я думал, что вставлю свой ответ на C # 6. Мне часто приходится настраивать тестовые данные, которые легко вводятся в код в виде списка кортежей. С парой функций расширения можно получить этот красивый, компактный формат, не повторяя имен в каждой записи.

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

Это дает IEnumerable - если вы хотите список, который вы можете добавить, просто добавьте ToList ().

Волшебство исходит от пользовательского расширения. Добавьте методы для кортежей, как описано в 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...

}

Единственное, что мне не нравится, это то, что типы отделены от имен, но если вы действительно не хотите создавать новый класс, тогда этот подход все равно позволит вам иметь читаемые данные.

3 голосов
/ 17 октября 2013

Для вашего второго примера, где вам нужно инициализировать новый List<T>, одна идея - создать анонимный список, а затем очистить его.

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

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

Или как метод расширения, должно быть проще:

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

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

Или, возможно, даже короче,

var list = new int[0].Select(x => new { Id = 0, Name = "" }).Tolist();
1 голос
/ 12 февраля 2019

Получив от этот ответ , я придумал два метода, которые могли бы выполнить задачу:

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

Вы можете использовать такие методы, как

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

Этот ответ имеет аналогичную идею, но я не видел ее до тех пор, пока не сделал эти методы.

0 голосов
/ 18 сентября 2012
static void Main()
{
    List<int> list = new List<int>();
    list.Add(2);
    list.Add(3);
    list.Add(5);
    list.Add(7);
}
0 голосов
/ 24 июня 2014

Попробуйте с этим:

var result = new List<object>();

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