简体   繁体   English

匿名 class 的通用列表

[英]A generic list of anonymous class

In C# 3.0 you can create anonymous class with the following syntax在 C# 3.0 中,您可以使用以下语法创建匿名 class

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

Is there a way to add these anonymous class to a generic list?有没有办法将这些匿名 class 添加到通用列表中?

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

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:)你明白了:)

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

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.如果您正在寻找泛型类型的空列表,请针对元组列表使用 Select 来创建空列表。 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();   

Not exactly, but you can say List<object> and things will work.不完全是,但你可以说List<object>并且事情会起作用。 However, list[0].Id won't work.但是, list[0].Id不起作用。

This will work at runtime in C# 4.0 by having a List<dynamic> , that is you won't get IntelliSense.这将在 C# 4.0 的运行时通过List<dynamic>工作,也就是说您不会获得 IntelliSense。

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

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 can do this in your code.您可以在代码中执行此操作。

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

If you are using C# 7 or above, you can use tuple types instead of anonymous types.如果您使用的是 C# 7 或更高版本,则可以使用元组类型而不是匿名类型。

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

In latest version 4.0, can use dynamic like below在最新版本 4.0 中,可以使用如下动态

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

I checked the IL on several answers.我在几个答案上检查了 IL。 This code efficiently provides an empty List:此代码有效地提供了一个空列表:

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

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. “动态”由添加的第一个值初始化。

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.您始终可以使用object而不是dynamic的,但尝试以真正的通用方式保持它,然后dynamic更有意义。

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.当我为自定义类型创建一个匿名列表时,我想到了这个。

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.这是另一种创建匿名类型列表的方法,它允许您从一个空列表开始,但仍然可以访问 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();

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:但是,如果您尝试在另一个 scope 中执行类似的操作,您将收到编译时错误,尽管它在运行时有效:

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 .问题是只有 Object 的成员在运行时可用,尽管智能感知会显示属性idname

In .net 4.0 a solution is to use the keyword dynamic istead of object in the code above.在 .net 4.0 中,解决方案是在上面的代码中使用关键字dynamic而不是object

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

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.对我来说这似乎有点“hacky”,但它有效 - 如果你真的需要一个列表并且不能只使用匿名数组。

This is an old question, but I thought I'd put in my C# 6 answer.这是一个老问题,但我想我会输入我的 C# 6 答案。 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().这给出了一个 IEnumerable - 如果你想要一个可以添加的列表,那么只需添加 ToList()。

The magic comes from custom extension Add methods for tuples, as described at https://stackoverflow.com/a/27455822/4536527 .魔法来自元组的自定义扩展 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...

} }

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.我唯一不喜欢的是类型与名称分开,但如果你真的不想制作一个新的 class 那么这种方法仍然可以让你拥有可读的数据。

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

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.对于第二个示例,您必须初始化一个新的List<T> ,一个想法是创建一个匿名列表,然后将其清除。

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

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.这个答案有一个类似的想法,但是直到我做了这些方法之后我才看到它。

Try with this:试试这个:

var result = new List<object>();

foreach (var test in model.ToList()) {
   result.Add(new {Id = test.IdSoc,Nom = test.Nom});
}
static void Main()
{
    List<int> list = new List<int>();
    list.Add(2);
    list.Add(3);
    list.Add(5);
    list.Add(7);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM