C# 12, Collection Expression의 대상 타입에 IEnumerable<T> 도 되네요.

선언코드:

public class MySequence<T>(IEnumerable<T> sequence) : IEnumerable<T>
{
    // 묵시적 변환을 위한 요구 조건.
    public MySequence<T> Create(IEnumerable<T> sequence) => 
        new (sequence);

    public MySequence(params T[] elements) : this((IEnumerable<T>)elements) { }
    
    public IEnumerator<T> GetEnumerator() => 
        sequence.GetEnumerator();
    
    IEnumerator IEnumerable.GetEnumerator() => 
        GetEnumerator();
}

사용 코드:

MySequence<int> mine = [1, 2, 3];
MySequence<int> empty = [];

DoWith([]);
DoWith(Enumerable.Empty<int>());

// ...
void Do(MySequnce<int> sequence)
{
   // ...
}

문서에서는 IEnumerable 도 포함된다는 말이 없는데 말이죠.

3 Likes

링크해 주신 문서에 분명히 명시돼 있습니다. ^^

Any type that supports a collection initializer, such as System.Collections.Generic.List<T>. Usually, this requirement means the type supports System.Collections.Generic.IEnumerable<T> and there's an accessible Add method to add items to the collection. There must be an implicit conversion from the collection expression elements' type to the collection's element type. For spread elements, there must be an implicit conversion from the spread element's type to the collection's element type.

위의 문장을 간단하게 정리하면 이렇습니다.

대괄호를 이용한 초기화 식은 배열뿐만 아니라, Span(ReadOnlySpan)과 (C# 3.0의) Collection Initializer를 지원하는 타입 및 C# 6.0의 확장 메서드로 Add를 지원하는 IEnumerable 타입에 적용할 수 있습니다.

이에 대한 예제 코드는 아래의 글에서 확인할 수 있습니다. ^^

닷넷: 2144. C# 12 - 컬렉션 식(Collection Expressions) (sysnet.pe.kr)

3 Likes

저는 위 부분을 아래와 같이 해석했습니다.

(Collection Expression 이) 변환 가능한 대상 타입은 System.Collections.Generic.IEnumerable<T> 를 지원하고, Add 메서드가 있어야 함을 의미한다.

List<T> 는 여기에 해당하지만, IEnumerable<T> 는 아니죠.
문서는 안되는 듯 서술되었지만, 실제로는 되고 있다는 점을 말씀드린 것입니다.

같은 맥락으로 C# 13 에서는 기본 타입을 List<T>로 할 예정이라고 합니다.

var collection = [1, 2, 3]; // var == List<int>
2 Likes
> IEnumerable<string> a = [];
> a.GetType()
[System.String[]]
> a == Enumerable.Empty<string>()
false
> a == Array.Empty<string>()
true
> 

지금은 뭘로 할당되나 봤더니 배열이군요!

5 Likes

배열이기 때문에, IEnumerable 이 호환되나 봅니다.
괜히 혼자 떠들썩했네요. ^^

코드를 작성하다가, IEnumerable 변수와 호환 문제로 컴파일 에러가 났는데, 결국은 다른 곳의 에러였네요.

1 Like

저도 대충 봤군요. 컴파일이 된다고 하는 말에 꽂혀서 MySequence 타입에 Add도 구현된 줄 알고 그렇게 답변한 것이었습니다.

그런데, 이상하군요. 처음 질문에 했던 예제로는 분명히 Add가 없다면서 컴파일 오류가 발생할 텐데요. 그러니까, 아래의 예제 코드로 해보면,

using System.Collections;

namespace ConsoleApp1;

internal class Program
{
    static void Main(string[] args)
    {
        MySequence<int> mine = [1, 2, 3];
    }
}

public class MySequence<T>(IEnumerable<T> sequence) : IEnumerable<T>
{
    // 묵시적 변환을 위한 요구 조건.
    public MySequence<T> Create(IEnumerable<T> sequence) =>
        new(sequence);

    public MySequence(params T[] elements) : this((IEnumerable<T>)elements) { }

    public IEnumerator<T> GetEnumerator() =>
        sequence.GetEnumerator();

    IEnumerator IEnumerable.GetEnumerator() =>
        GetEnumerator();
}

다음과 같이 컴파일 오류가 발생합니다.

error CS1061: ‘MySequence’ does not contain a definition for ‘Add’ and no accessible extension method ‘Add’ accepting a first argument of type ‘MySequence’ could be found (are you missing a using directive or an assembly reference?)

저 오류가 발생하지 않는다는 건가요?

2 Likes

헐… 저는 안 납니다.

1 Like

저 소스코드로만 빌드했는데도 오류가 안 난다는 건가요? 오호~~~ 흥미롭군요. ^^

혹시 빌드된 결과물을 첨부해 주실 수 있을까요?

1 Like

기존 코드가 박혀 있던 프로젝트를 드릴 수는 없어서, 새로 작성했는데, 그건 오류가 뜨네요.
그리고, 기존 프로젝트를 다시 열어 보니까 오류 뜹니다.

참고로, 오전에 VS 업데이트 했습니다.

그런데, 요건 오류가 뜨는데,

MySequence<int> mine = [1, 2, 3];

요건 안뜨네요.

IEnumerable<int> ints = [1, 2, 3];
MySequence<int> mine = [];
1 Like

애당초 다른 소스코드와 섞여있는 상태에서 테스트하신 거군요.

기존 프로젝트의 소스코드에서 "mine.Add"라고 해보세요. 100% IEnumerable 등에 대해 Add 확장 메서드가 포함돼 있을 것입니다.

오류가 안 뜨는 2가지 예제는, 1) favdra 님이 예를 든 것처럼 C# 컴파일러가 배열로 추론하기 때문이고, 2) 빈 초기화 구문이기 때문에 Add 할 필요가 없어 그에 대한 확장 메서드가 필요 없기 때문에 오류가 없는 것입니다.

프로젝트의 익스텐션은 이게 다입니다.

2 Likes

비주얼 스튜디오 편집기에서 mine.Add 라고"."을 찍었을 때 나오는 인텔리센스에 Add 메서드가 없다는 건가요?

1 Like

예, 없습니다.

1 Like

일단 제 수준에서는 빌드 결과물이 없어 더 이상의 추적이 불가능하군요. ^^; 남은 해답은 @BigSquare 님만이 찾을 수 있을 듯합니다.

1 Like

해답은 다음 생에… ^^.
지금은 문서 대로 동작하니까요.

그래도, 요소가 없는 컬렉션 식이 IEnumerable 에 할당가능하다는 디테일을 배울 수 있어 좋네요.

2 Likes

좋은 extension 퍼가요~:heart:

1 Like

메서드 이름밖에 안 나왔는데, 좋다니요.
필요하면 코드 다 드릴 수는 있는데, 그렇게 활용 가치가 있는 것은 아니라서, 좀 그렇습니다. ^^?

1 Like

앗, 코드 공유 해주시면 감사하겠습니다…ㅋㅋㅋ