익명 클래스의 일반적인 목록


416

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

2
모든 객체는 배열에서 동일하게 입력해야합니다. 드물게 캐스트, 특히 null에 대한 도움이 필요할 수도 있습니다.new[] { new{ Id = (int?)null, Name = "Foo" }, new { Id = (int?)1, Name = "Foo" }}
AaronLS

1
익명 형식은 임시 저장소로 사용하도록 설계되었으며 대부분의 경우 Select (i => new {i.ID, i.Name})을 사용하여 LINQ select 문에서 만듭니다. 당신이 LINQ.Where 문으로 잠시 절을 다시 정의 할 경우 올바른 유형의는 IEnumerable을 반환하는 당신은 이제까지 목록을 필요가 없습니다 당신이 그랬다면 당신은 단지에 ToList를 호출 할 수 있습니다
MikeT

답변:


427

당신은 할 수 있습니다 :

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

당신은 아이디어를 얻는다 :)


32
@DHornpout : List <T>가 아닌 배열을 제공합니다.
Jon Skeet

23
@DHornpout : "Using System.Linq;"가 있습니까 파일 상단에? ToList는 LINQ 연산자입니다.
Jon Skeet

5
"System.Linq 사용"을 포함해야합니다. 감사.
DHornpout

2
Visual Studio에서는 intellisense가 참조 확장 메서드 (참조 유형과 동일)가있는 어셈블리의 누락 된 포함을 발견하는 데 더 도움이되지 않는 것처럼 보입니다.
LOAS

3
이 사람은 어디에나 있고, 오늘 8 개의 질문을 검색했으며, 7 명이 그에 의해 답변했습니다.
Kugan Kumar

109

여기에 답이 있습니다.

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, 코드는 끝에 .ToList ()없이 작동해야합니다.
DHornpout

3
좋습니다. 이제 새 {} 줄을 select 문으로 바꾸는 예제가 필요합니다. var list = sourceList.Select (o => new {o.ModelId, o.PartNumber, o.Quantity}). ToList ();
topwik

@towpse 그것에 대한 해결책이 있습니까?
Kiquenet

@Dutt, List <T>를 반환하는 메서드 (함수)를 사용하는 경우 샘플은 무엇입니까?
Kiquenet

이제 메소드 string.Join와 문자열 보간이 있으므로 foreachand 를 사용할 필요가 없습니다 Format.
realsonic

61

이를 수행하는 방법에는 여러 가지가 있지만 여기서 응답 중 일부는 가비지 요소가 포함 된 목록을 작성하므로 목록을 지워야합니다.

제네릭 형식의 빈 목록을 찾으려면 튜플 목록에서 선택을 사용하여 빈 목록을 만듭니다. 어떤 요소도 인스턴스화되지 않습니다.

빈 목록을 만드는 하나의 라이너는 다음과 같습니다.

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

대안으로, 당신은 빈리스트를 만들기 위해 아래와 같은 것을 할 수 있습니다 (그러나, 나는 채워진 Tuples 컬렉션에도 사용할 수 있기 때문에 첫 번째 예를 선호합니다).

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

1
나는이 방법을 많이 좋아한다. 고마워 폴! Tuples를 사용할 수있는 좋은 날입니다. xD
Brady Liles 2016 년

나는 이것을 좋아한다. 전달할 객체에 대한 구체적인 선언을하는 것이 좋습니다.
Morvael

니스 나는 그것을 다시 내 목록 시간을 삭제 포함 단지 완성을 writting 코드
JoshBerke

아이디어 주셔서 감사합니다. 제안, 당신이 사용하는 경우 더미 목록 할당을 피할 수 있습니다Enumerable.Empty<object>().Select(o=>definition).ToList()
BrainStorm.exe

45

정확히는 아니지만 말할 수 List<object>있고 작동합니다. 그러나 list[0].Id작동하지 않습니다.

이것은 C # 4.0 에서 런타임 에 작동 하여List<dynamic> IntelliSense를 얻지 못합니다.


그러나 목록의 항목에 대한 컴파일러 인텔리전스 지원이 없다는 의미에서 강력하게 형식화되지 않았습니다.
Joel Coehoorn

31
이것이 사람들이 역동적으로 할 것을 두려워하는 일입니다.
erikkallen

2
나는 그것이 좋은 생각 이라고 말하지는 않았지만 가능했다 :-) 예를 들어 루비에서 객체를 저장한다면 필요할 수 있습니다.
Jeff Moser

2
그러나 이러한 경우 소스 유형은 결국 동적이므로 익명 유형에 List <dynamic>을 사용하는 것은 의미가 없습니다.
Dykam

1
매우 도움이됩니다. 특히 익명 항목을 추가하기 전에 목록을 정의해야하는 경우.
Karlth

24

나는 추측한다

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

예,이 솔루션은 익명 배열 초기화를 해결하는 데 도움이됩니다. 감사.
DHornpout

1
메소드 이름 뒤에 약간의 <T>를 넣으십시오.
Martin

21

나는 보통 다음을 사용합니다. 주로 빈 목록으로 시작합니다.

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

반복 방법을 사용하면 다음을 수행 할 수 있습니다.

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

.. 첫 번째 항목이 이미 추가 된 초기 목록을 제공합니다.


2
빈 목록으로 시작할 필요는 없습니다. Range (0,1)을 수행하고 select 문에서 첫 번째 개체를 첫 번째 개체로 만들 수 있습니다.
Matthew M.

1
첫 번째 항목이 무엇인지 아는 경우 (예에서와 같이) 빈 목록으로 시작할 필요가 없습니다. 여러 번 나는 이것을 중간 파일 / 데이터 소스를 구문 분석하는 데 사용하고 LINQ 투영 시나리오에서 사용할 때까지 첫 번째 실제 항목에 액세스하지 않으므로 첫 번째 레코드를 건너 뛸 필요가 없습니다.
Rostov

19

코드에서이 작업을 수행 할 수 있습니다.

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

11

최신 버전 4.0에서는 아래와 같이 동적을 사용할 수 있습니다

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

10

나는 몇 가지 답변에서 IL을 확인했습니다. 이 코드는 빈 목록을 효율적으로 제공합니다.

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

1
편집을 거부 할 이유가 있습니까? 다음 답변은을 반환 IEnumerable하지만 내 버전은을 반환합니다 List.
Necronomicron

나는이 방법을 선호하거나 더 가까이 한 이 답변 :new object[] { }.Select(o => new { Id = default(int), Name = default(string) }).ToList()
palswim

8

여기 내 시도가 있습니다.

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

나는 사용자 정의 유형에 대한 익명 목록을 만드는 것과 비슷한 것을 썼을 때 이것을 생각해 냈습니다.


8

동적 목록을 만들 수 있습니다.

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

"동적"은 추가 된 첫 번째 값으로 초기화됩니다.


7

이 대신에 :

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

문제는 intellisense에 속성 idname 이 표시되지만 런타임에 Object 멤버 만 사용할 수 있다는 것 입니다.

.net 4.0에서 해결책은 위의 코드에서 객체 대신 키워드 dynamic istead 를 사용하는 것 입니다.

또 다른 해결책은 리플렉션을 사용하여 속성을 얻는 것입니다.

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

다음은 빈 목록으로 시작할 수 있지만 여전히 IntelliSense에 액세스 할 수있는 익명 유형 목록을 작성하는 다른 방법입니다.

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

첫 번째 항목을 유지하려면 문자열에 한 글자 만 넣으십시오.

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

배열 이니셜 라이저가 작동하지만 아주 나쁜 방법입니다 수 있으므로 문자열을 사용
MikeT

위의 답변 중 대부분이 특별히 "좋은"관행은 아니지만 질문의 본질로 인해 주어진 것입니다. 익명 유형은 실제로 이런 방식으로 작동하도록 설계되지 않았습니다. 왜 내 방법이 다른 방법보다 "나쁜"지 궁금합니다. 내가 놓친 것?
Brackus

질문은 나쁜 연습 자체에 대한 좋은 연습 답변이 없다는 것을 요구하는 것이 맞습니다. 그러나 문자열을 사용하여 문자 배열을 생성 한 다음 사용자가 원하는 것의 배열로 변환하기 때문에 비효율적 인 불필요한 복싱 및 언 박싱 생성을 언급하지 않는 관련없는 유형
MikeT

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

5

이것은 오래된 질문이지만 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에 설명 된대로 튜플에 대한 사용자 정의 확장 Add 메소드에서 비롯됩니다 .

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

컬렉션 초기화 프로그램을 제안한 사람이 아무도 없습니다. 이 방법은 목록을 만들 때만 객체를 추가 할 수 있으므로 이름은 가장 좋은 방법처럼 보입니다. 배열을 만든 다음 목록으로 변환 할 필요가 없습니다.

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

항상 object대신 사용할 수 dynamic있지만 일반적인 방식으로 유지하는 dynamic것이 더 합리적입니다.


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

그것은 나에게 약간의 "해킹"것처럼 보이지만 작동합니다. 실제로 목록이 필요하고 익명 배열을 사용할 수없는 경우 작동합니다.


3

두 번째 예에서는 new를 초기화해야하는 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();

2

C # 7 이상을 사용하는 경우 익명 유형 대신 튜플 유형을 사용할 수 있습니다.

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

1

이 답변 에서 파생 된 작업을 수행 할 수있는 두 가지 방법을 생각해 냈습니다.

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

이 대답 은 비슷한 생각을 가지고 있지만 그 방법을 만든 후에야 그것을 알 수 없었습니다.



당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.