匿名类的通用列表

时间:2009-03-04 22:08:47

标签: c# .net generics anonymous-types

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

22 个答案:

答案 0 :(得分:394)

你可以这样做:

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

有很多方法可以为这只猫设置皮肤,但基本上它们都会在某处使用类型推断 - 这意味着你必须调用泛型方法(可能作为扩展方法)。另一个例子可能是:

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

var list = CreateList(o, o1);

你明白了这一点:)

答案 1 :(得分:95)

这是答案。

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

答案 2 :(得分:47)

有很多方法可以做到这一点,但这里的一些响应是创建一个包含垃圾元素的列表,这需要您清除列表。

如果要查找泛型类型的空列表,请使用“针对元组列表选择”来创建空列表。没有元素会被实例化。

这是创建空列表的单行:

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

然后您可以使用通用类型添加它:

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

作为替代方案,您可以执行以下操作来创建空列表(但是,我更喜欢第一个示例,因为您也可以将它用于填充的元组集合):

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

答案 3 :(得分:41)

不完全是,但你可以说List<object>并且事情会奏效。但是,list[0].Id无效。

这将在C#4.0中通过List<dynamic>在运行时中运行,即您将无法获得IntelliSense。

答案 4 :(得分:23)

我想

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

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

会奏效。

你也可以考虑这样写:

void something() {
    var String = string.Emtpy;
    var Integer = int.MinValue;
    var emptyListOfAnonymousType = CreateEmptyGenericList(new { Id = Integer, Name = String });
}

答案 5 :(得分:19)

我通常使用以下内容;主要是因为你然后用一个空的列表“开始”。

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

最近,我一直在这样写:

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

使用repeat方法还可以执行以下操作:

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

..它为您提供了已添加第一个项目的初始列表。

答案 6 :(得分:19)

您可以在代码中执行此操作。

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

答案 7 :(得分:10)

我在几个答案上检查了IL。此代码有效地提供了一个空List:

    using System.Linq;
    …
    var list = new[]{new{Id = default(int), Name = default(string)}}.Skip(1).ToList();

答案 8 :(得分:9)

在最新的4.0版本中,可以使用如下的动态

var list = new List<dynamic>();
        list.Add(new {
            Name = "Damith"
    });
        foreach(var item in list){
            Console.WriteLine(item.Name);
        }
    }

答案 9 :(得分:7)

这是我的尝试。

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

当我为自定义类型制作匿名列表时,我想出了类似的东西。

答案 10 :(得分:6)

这是另一种创建匿名类型列表的方法,它允许您从空列表开始,但仍然可以访问IntelliSense。

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

如果你想保留第一项,只需在字符串中加一个字母。

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

答案 11 :(得分:5)

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

答案 12 :(得分:5)

而不是:

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中,解决方案是在上面的代码中使用关键字动态而不是对象

另一种解决方案是使用反射来获取属性

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

答案 13 :(得分:4)

您可以创建动态列表。

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

&#34;动态&#34;由第一个增加值初始化。

答案 14 :(得分:3)

对于你的第二个例子,你必须初始化一个新的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();

答案 15 :(得分:3)

你可以这样做:

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

对我来说这似乎有些“hacky”,但它确实有效 - 如果你真的需要一个列表并且不能只使用匿名数组。

答案 16 :(得分:3)

这是一个老问题,但我想我已经加入了我的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...

}

我唯一不喜欢的是这些类型与名称分开,但如果您真的不想创建新类,那么这种方法仍然会让您拥有可读数据。< / p>

答案 17 :(得分:1)

源自this answer,我想到了两种可以完成任务的方法:

a

您可以使用类似的方法

a+0

This answer有一个类似的想法,但是直到完成这些方法后我才看到它。

答案 18 :(得分:1)

我很惊讶没有人建议使用集合初始值设定项。这种方法只能在创建列表时添加对象,因此要添加名称,但是这似乎是执行此操作的最佳方法。无需创建数组,然后将其转换为列表。

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

您始终可以使用object而不是dynamic,但是尝试以一种真实的通用方式进行保存,那么dynamic更为有意义。

答案 19 :(得分:0)

试试这个:

var result = new List<object>();

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

答案 20 :(得分:0)

如果您使用的是C#7或更高版本,则可以使用tuple types代替匿名类型。

var myList = new List<(int IntProp, string StrProp)>();
myList.Add((IntProp: 123, StrProp: "XYZ"));

答案 21 :(得分:-13)

static void Main()
{
    List<int> list = new List<int>();
    list.Add(2);
    list.Add(3);
    list.Add(5);
    list.Add(7);
}