[C#] 왜 C #에서 배열처럼 List를 초기화 할 수 있습니까?

오늘 나는 C #에서 내가 할 수 있다는 것을 알게되어 놀랐습니다.

List<int> a = new List<int> { 1, 2, 3 };

왜 이렇게 할 수 있습니까? 어떤 생성자가 호출됩니까? 내 수업으로 어떻게 할 수 있습니까? 이것이 배열을 초기화하는 방법이지만 배열은 언어 항목이며 목록은 간단한 객체입니다 …



답변

이것은 .NET의 컬렉션 초기화 구문의 일부입니다. 다음과 같은 경우 생성 한 컬렉션에서이 구문을 사용할 수 있습니다.

  • 그것은 IEnumerable(바람직하게는 IEnumerable<T>)

  • 이름이 지정된 메소드가 있습니다 Add(...)

기본 생성자가 호출 된 다음 Add(...)초기화 프로그램의 각 멤버에 대해 호출됩니다.

따라서이 두 블록은 거의 동일합니다.

List<int> a = new List<int> { 1, 2, 3 };

List<int> temp = new List<int>();
temp.Add(1);
temp.Add(2);
temp.Add(3);
List<int> a = temp;

당신 이 원하는 경우, 예를 들어 성장 하는 동안 크기를 초과하지 않도록 대체 생성자를 호출 있습니다List<T> .

// Notice, calls the List constructor that takes an int arg
// for initial capacity, then Add()'s three items.
List<int> a = new List<int>(3) { 1, 2, 3, }

Add()방법은 단일 항목을 취할 필요가 없습니다. 예를 들어 두 가지 항목 Add()Dictionary<TKey, TValue>취하는 방법은 다음과 같습니다.

var grades = new Dictionary<string, int>
    {
        { "Suzy", 100 },
        { "David", 98 },
        { "Karen", 73 }
    };

대략 다음과 같습니다.

var temp = new Dictionary<string, int>();
temp.Add("Suzy", 100);
temp.Add("David", 98);
temp.Add("Karen", 73);
var grades = temp;

따라서 이것을 자신의 클래스에 추가하려면 언급 한 것처럼 IEnumerable(다시, 바람직하게 는) 구현 IEnumerable<T>하고 하나 이상의 Add()메소드를 작성하면됩니다 .

public class SomeCollection<T> : IEnumerable<T>
{
    // implement Add() methods appropriate for your collection
    public void Add(T item)
    {
        // your add logic    
    }

    // implement your enumerators for IEnumerable<T> (and IEnumerable)
    public IEnumerator<T> GetEnumerator()
    {
        // your implementation
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

그런 다음 BCL 컬렉션과 마찬가지로 사용할 수 있습니다.

public class MyProgram
{
    private SomeCollection<int> _myCollection = new SomeCollection<int> { 13, 5, 7 };

    // ...
}

(자세한 내용은 MSDN을 참조하십시오 )


답변

그것은 구문 설탕 이라고 불립니다 .

List<T> “간단한”클래스이지만 컴파일러는 인생을 편하게하기 위해 특별한 대우를합니다.

이것을 소위 collection initializer 라고 합니다. 구현 IEnumerable<T>Add방법 이 필요합니다 .


답변

C # 버전 3.0 사양 에 따르면 “컬렉션 이니셜 라이저가 적용되는 컬렉션 개체는 정확히 하나의 T에 대해 System.Collections.Generic.ICollection을 구현하는 형식이어야합니다.”

그러나이 정보는이 글을 쓰는 시점에서 부정확 한 것으로 보입니다. 아래 주석에서 Eric Lippert의 설명을 참조하십시오.


답변

기본적으로 컬렉션이 Add 메소드를 구현해야하며 컬렉션 작업을 수행하는 컬렉션 이니셜 라이저 덕분에 작동합니다.


답변

컬렉션 이니셜 라이저의 또 다른 멋진 점은 여러 가지 오버로드 된 Add메소드를 가질 수 있고 동일한 이니셜 라이저에서 모두 호출 할 수 있다는 것입니다! 예를 들어 다음과 같이 작동합니다.

public class MyCollection<T> : IEnumerable<T>
{
    public void Add(T item, int number)
    {

    }
    public void Add(T item, string text)
    {

    }
    public bool Add(T item) //return type could be anything
    {

    }
}

var myCollection = new MyCollection<bool>
{
    true,
    { false, 0 },
    { true, "" },
    false
};

올바른 과부하를 호출합니다. 또한 name을 사용하는 메소드 만 찾으면 Add리턴 유형이 무엇이든 될 수 있습니다.


답변

구문과 같은 배열은 일련의 Add()호출 로 바뀌고 있습니다.

훨씬 더 흥미로운 예제에서 이것을 보려면 C #에서 처음으로 잘못된 두 가지 흥미로운 일을하는 다음 코드를 고려하십시오 .1) 읽기 전용 속성 설정, 2) 초기화와 같은 배열로 목록 설정.

public class MyClass
{
    public MyClass()
    {
        _list = new List<string>();
    }
    private IList<string> _list;
    public IList<string> MyList
    {
        get
        {
            return _list;
        }
    }
}
//In some other method
var sample = new MyClass
{
    MyList = {"a", "b"}
};

이 코드는 완벽하게 작동하지만 1) MyList는 읽기 전용이며 2) 배열 이니셜 라이저로 목록을 설정했습니다.

이것이 작동하는 이유는 객체 초기화 프로그램의 일부인 코드에서 컴파일러는 항상 {}구문을 Add()읽기 전용 필드에서도 완벽하게 유효한 일련의 호출로 바꾸기 때문입니다.


답변