Anonim sınıfın genel listesi


416

C # 3.0'da, aşağıdaki sözdizimiyle anonim bir sınıf oluşturabilirsiniz

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

Bu anonim sınıfı genel bir listeye eklemenin bir yolu var mı?

Misal:

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

Başka bir örnek:

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

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

2
Tüm nesnelerin dizide aynı şekilde yazılması gerektiğini unutmayın. Nadiren, özellikle new[] { new{ Id = (int?)null, Name = "Foo" }, new { Id = (int?)1, Name = "Foo" }}
null'lar

1
anonim türler geçici depolama olarak kullanılmak üzere tasarlanmıştır, çoğu durumda bunları Select (i => new {i.ID, i.Name}) kullanarak LINQ select deyiminde oluşturursunuz; Bir LINQ.Where deyimi içine ederken maddesini yeniden tanımlamak durumunda Doğru türde bir IEnumerable dönecekti hangi Hiç listesine ihtiyacımız olmamalı ve Bilseydin sonra sadece üzerinde ToList çağırabilir
miket

Yanıtlar:


427

Şunları yapabilirsiniz:

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

Bu kedinin derisini yüzmenin birçok yolu vardır, ancak temelde hepsi bir yerde tip çıkarımı kullanacaktır - bu, genel bir yöntem (muhtemelen bir genişletme yöntemi olarak) çağırmanız gerektiği anlamına gelir. Başka bir örnek şunlar olabilir:

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

var list = CreateList(o, o1);

Kaptın bu işi :)


32
@DHornpout: Liste <T> yerine bir dizi verir.
Jon Skeet

23
@DHornpout: "System.Linq kullanarak;" Dosyanızın üst kısmında? ToList bir LINQ operatörüdür.
Jon Skeet

5
Anladım .. "System.Linq kullanarak" eklemeniz gerekir. Teşekkürler.
DHornpout

2
Visual Studio'da, uyumsuzluğun başvurulan uzantı yöntemleri (başvurulan türlerle aynı) olan derleme eksik içeriklerini ortaya çıkarmada daha yararlı olmadığı anlaşılıyor.
LOAS

3
bu adam her yerde, bugün 8 soru aradı, 7 cevapladı.
Kugan Kumar

109

İşte cevap.

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

12
Dutt, kodunuz sonunda .ToList () olmadan çalışmalıdır.
DHornpout

3
Tamam, şimdi yeni {} satırlarını select deyimiyle değiştirme örneğine ihtiyacımız var. var list = sourceList.Select (o => yeni {o.ModelId, o.PartNumber, o.Quantity}). ToList ();
topwik

@towpse bu konuda herhangi bir çözüm var mı?
Mart'ta Kiquenet

@Dutt, <T> Listesini döndüren bir yöntem (işlev) kullanırsam herhangi bir örnek?
Kiquenet

Şimdi orada yöntemdir string.Joingerek kullanımı çok ve dize enterpolasyon foreachve Format.
realsonic

61

Bunu yapmanın birçok yolu vardır, ancak buradaki yanıtların bazıları, listeyi temizlemenizi gerektiren çöp öğeleri içeren bir liste oluşturuyor.

Genel türde boş bir liste arıyorsanız, boş listeyi yapmak için Tuples List'e karşı bir Select kullanın. Hiçbir öğe somutlaştırılamaz.

Boş bir liste oluşturmak için tek astar:

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

Daha sonra genel türünüzü kullanarak ekleyebilirsiniz:

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

Alternatif olarak, boş listeyi oluşturmak için aşağıdaki gibi bir şey yapabilirsiniz (Ancak, ilk örneği tercih ederim çünkü doldurulmuş bir Tuples koleksiyonu için de kullanabilirsiniz):

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

1
Bu yolu çok seviyorum. Teşekkürler Paul! Tuples'ı kullanabileceğiniz her zaman iyi bir gün! xD
Brady Liles

Bunu severim. İçine geçeceğim nesnenin bir tür somut beyanına sahip olmak güzel.
İçine Morvael

Nice Sadece yeniden yazmak için liste zamanımı temizleme dahil kod yazmayı bitirdim
JoshBerke

Fikir için teşekkürler. Bir öneri, kullanıyorsanız bir kukla liste ayırmaktan kaçınabilirsinizEnumerable.Empty<object>().Select(o=>definition).ToList()
ayırmaktan

45

Tam olarak değil, ama söyleyebilirsin List<object>ve işler işe yarayacak. Ancak, list[0].Idçalışmaz.

Bu, C # 4.0'da çalışma zamanında bir a'ya sahip List<dynamic>olacak, yani IntelliSense alamayacaksınız.


Bununla birlikte, listedeki öğeler için derleyici istihbarat desteğine sahip olmayacağınız için güçlü bir şekilde yazılmamıştır.
Joel Coehoorn

31
İnsanların dinamikle yapmasından korktuğum şey budur.
erikkallen

2
Harika bir fikir olduğunu söylemedim , ama bunun mümkün olduğunu söyleyebilirim :-) Örneğin Ruby'den nesne saklamak için bir ihtiyaç olabilir.
Jeff Moser

2
Ancak bu durumlarda kaynak türü dinamiktir, anonim türler için bir <dinamik> Listesi kullanmak mantıklı değildir.
Dykam

1
Çok yararlı. Özellikle listeye anonim öğeler eklenmeden önce tanımlanması gerekiyorsa.
Karlth

24

sanırım

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

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

çalışacak.

Ayrıca şöyle yazmayı da düşünebilirsiniz:

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

Evet, bu çözüm Anonim dizinin başlatılmasının çözülmesine yardımcı olacaktır. Teşekkürler.
DHornpout

1
Yöntem adından sonra biraz <T> koyun.
Martin

21

Genellikle aşağıdakileri kullanırım; çünkü boş bir listeyle "başlıyorsunuz".

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

Son zamanlarda bunun yerine şöyle yazıyorum:

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

Tekrarlama yöntemini kullanmak şunları yapmanıza da izin verir:

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

.. ilk listenin eklenmiş olduğu ilk listeyi verir.


2
Boş bir listeyle başlamanız gerekmez - Aralık (0,1) 'i yapabilir ve select deyimindeki ilk nesnenizi ilk nesne yapabilirsiniz.
Matthew

1
Boş bir listeyle başlamanız gerekmez - ilk öğenin ne olduğunu (örnekte olduğu gibi) biliyorsanız, yorumunuzda haklısınız demektir. Çoğu zaman bunu bir ara dosya / veri kaynağını ayrıştırmak için kullanıyorum ve bir LINQ projeksiyon senaryosunda kullanılana kadar ilk gerçek öğeye erişemiyorum (ve böylece ilk kaydı atlamak için hesaba gerek yok).
Rostov

19

Bunu kodunuzda yapabilirsiniz.

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

11

En son sürüm 4.0, aşağıdaki gibi dinamik kullanabilirsiniz

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

10

IL'yi birkaç cevapta kontrol ettim. Bu kod verimli bir şekilde boş bir Liste sağlar:

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

1
Düzenlememi reddetmek için herhangi bir neden var mı? Yanıtın ardından IEnumerable, sürümüm dönerken List, OP'nin tam olarak sorduğu şey.
Necronomicron

Bu yaklaşımı, hatta bu cevaba daha yakın olanı tercih ediyorum :new object[] { }.Select(o => new { Id = default(int), Name = default(string) }).ToList()
palswim

8

İşte benim girişimim.

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

Özel bir tür için Anonim Liste yapmak için benzer bir şey yazdığımda bununla geldim.


8

Dinamik bir liste oluşturabilirsiniz.

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

"dinamik" ilk katma değer ile başlatılır.


7

Bunun yerine:

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

Bunu yapabilirsin:

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

Ancak, çalışma zamanında çalışmasına rağmen başka bir kapsamda böyle bir şey yapmaya çalışırsanız bir derleme zamanı hatası alırsınız:

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

Sorun, intellisense özellik kimliğini ve adını göstermesine rağmen, çalışma zamanında yalnızca Object üyelerinin kullanılabilir olmasıdır .

Net 4.0'da bir çözüm yukarıdaki kodda nesnenin dinamik istead anahtar sözcüğünü kullanmaktır .

Başka bir çözüm, özellikleri elde etmek için yansıma kullanmaktır

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

7

Boş bir listeyle başlamanıza izin veren ancak yine de IntelliSense'e erişmenizi sağlayan anonim türlerin bir listesini oluşturmanın başka bir yöntemi.

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

İlk öğeyi saklamak istiyorsanız, dizeye bir harf koyun.

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

Bir dizgiyi dizi başlatıcısı olarak kullanmak işe yarayabilir, ancak çok kötü bir uygulamadır
MikeT

Yukarıdaki cevapların çoğunun özellikle "iyi" bir uygulama olmadığını söyleyebilirim, fakat bu sorunun niteliği nedeniyle verilmişti. Anonim türler bu şekilde çalışacak şekilde tasarlanmamıştır. Yine de yöntemimin neden diğerlerinden daha kötü olduğunu merak ediyorum? Kaçırdığım bir şey mi var?
Brackus

soru iyi bir uygulama yanıtı olamaz kötü bir şey soruyor haklısın, ama karakter dizisi oluşturmak için bir dize kullandığınız ve daha sonra bunu kullanıcının istediği bir dizi haline dönüştürdüğünüz için verimsiz gereksiz boks ve unboxing üretmekten bahsetmeyen ilgisiz türlerdir
MikeT

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

5

Bu eski bir soru, ama C # 6 cevabımı vereceğimi düşündüm. Sıklıkla tuples listesi olarak kod içine kolayca girilen test verilerini ayarlamak zorundayım. Birkaç uzantı işlevi ile, her girişteki adları tekrar etmeden bu güzel, kompakt biçime sahip olmak mümkündür.

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

Bu bir IEnumerable verir - ekleyebileceğiniz bir liste istiyorsanız ToList () ekleyin.

Sihir, özel uzantıdan gelir . Https://stackoverflow.com/a/27455822/4536527 adresinde açıklandığı gibi Tuples için yöntemler ekleyin .

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...

}

Sevmediğim tek şey, türlerin isimlerden ayrılmasıdır, ancak gerçekten yeni bir sınıf yapmak istemiyorsanız, bu yaklaşım yine de okunabilir verilere sahip olmanıza izin verecektir.


4

Kimse koleksiyon başlatıcıları önermediğine çok şaşırdım. Bu şekilde yalnızca liste oluşturulduğunda nesne eklenebilir, bu nedenle ad, ancak bunu yapmanın en güzel yolu gibi görünür. Bir dizi oluşturmanıza ve ardından bir listeye dönüştürmenize gerek yoktur.

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

Bunun objectyerine her zaman kullanabilirsiniz , dynamicancak gerçek bir şekilde tutmaya çalışmak dynamicdaha mantıklıdır.


3

Bunu şu şekilde yapabilirsiniz:

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

Bana biraz "hacky" gibi görünüyor, ama işe yarıyor - eğer gerçekten bir listeye ihtiyacınız varsa ve sadece anonim diziyi kullanamazsanız.


3

Yeni bir örnek başlatmanız gereken ikinci örneğiniz için, List<T>fikirlerden biri anonim bir liste oluşturmak ve ardından listeyi temizlemektir.

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

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

Veya bir genişletme yöntemi olarak daha kolay olmalıdır:

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

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

Ya da muhtemelen daha da kısa,

var list = new int[0].Select(x => new { Id = 0, Name = "" }).Tolist();

2

C # 7 veya üstünü kullanıyorsanız , anonim türler yerine tuple türlerini kullanabilirsiniz .

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

1

Bu cevaptan yola çıkarak , görevi yerine getirebilecek iki yöntem buldum:

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

Gibi yöntemleri kullanabilirsiniz

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

Bu cevabın benzer bir fikri var, ama bu yöntemleri yapana kadar görmedim.


0

Şunu deneyin:

var result = new List<object>();

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

Anonim türün listesi nerede?
Micha Wiedenmann

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

5
Burada anonim sınıf görmüyorum.
Andrew Barber
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.