匿名类的泛型列表

在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});
....
}
423435 次浏览

不完全是,但你可以说List<object>,事情就会工作。然而,list[0].Id将不起作用。

这将在c# 4.0中通过List<dynamic>工作,也就是说你不会得到智能感知。

你可以这样做:

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

你懂的。

我猜

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

你可以这样做:

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

对我来说,这似乎有点“俗气”,但它是可行的——如果你真的需要一个列表,不能只使用匿名数组。

这就是答案。

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

而不是这样:

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的成员在运行时可用,尽管智能感知会显示属性id的名字

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

下面是我的尝试。

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

当我为自定义类型编写类似的匿名列表时,我想到了这个方法。

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

您可以在代码中这样做。

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

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

我通常使用以下方法;主要是因为你从一个空列表开始。

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

. .这将为您提供已经添加了第一项的初始列表。

试试这个:

var result = new List<object>();


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

下面是另一种创建匿名类型列表的方法,它允许你从一个空列表开始,但仍然可以访问智能感知。

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

如果您想保留第一项,只需在字符串中放入一个字母。

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

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

如果您正在寻找泛型类型的空列表,请对元组列表使用Select以生成空列表。没有元素将被实例化。

下面是创建空列表的一行代码:

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

我检查了几个答案的IL。这段代码有效地提供了一个空列表:

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

这是一个老问题,但我想我会把我的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()。

魔力来自于元组的自定义扩展Add方法,如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...

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

在最新版本4.0中,可以像下面这样使用动态

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

您可以创建一个动态列表。

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

"dynamic"由第一个添加的值初始化。

这个答案派生,我提出了两个可以执行该任务的方法:

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

这个答案有一个类似的想法,但我没有看到它,直到我做了这些方法。

我很惊讶居然没有人建议集合初始化器。这种方法只能在创建列表时添加对象,因此得名,但它似乎是最好的方法。不需要创建一个数组,然后将其转换为列表。

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

你总是可以用object来代替dynamic,但是如果你试图用真正的泛型方式来使用它,那么dynamic就更有意义了。

如果你使用c# 7或更高版本,你可以使用tuple类型来代替匿名类型。

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