오늘 나는 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()
읽기 전용 필드에서도 완벽하게 유효한 일련의 호출로 바꾸기 때문입니다.