다음을 통해 공유


확장 선언(C# 참조)

C# 14부터 최상위 수준인 비제너릭 static class 선언은 컨테이너를 사용하여 extension확장 멤버를 선언할 수 있습니다. 확장 멤버는 메서드 또는 속성이며 인스턴스 또는 정적 멤버로 표시될 수 있습니다. 이전 버전의 C#에서는 최상위 비제네릭 정적 클래스에 선언된 정적 메서드의 첫 번째 매개 변수에 한정자로 추가하여 this 메서드를 사용하도록 설정합니다.

블록은 extension 확장 멤버의 형식과 수신기를 지정합니다. 선언 내에서 메서드 및 속성을 선언할 extension 수 있습니다. 다음 예제에서는 인스턴스 확장 메서드 및 인스턴스 속성을 정의하는 단일 확장 블록을 선언합니다.

public static class NumericSequences
{
    extension(IEnumerable<int> sequence)
    {
        public IEnumerable<int> AddValue(int operand)
        {
            foreach (var item in sequence)
            {
                yield return item + operand;
            }
        }

        public int Median
        {
            get
            {

                var sortedList = sequence.OrderBy(n => n).ToList();
                int count = sortedList.Count;
                int middleIndex = count / 2;

                if (count % 2 == 0)
                {
                    // Even number of elements: average the two middle elements
                    return (sortedList[middleIndex - 1] + sortedList[middleIndex]);
                }
                else
                {
                    // Odd number of elements: return the middle element
                    return sortedList[middleIndex];
                }
            }
        }

        public int this[int index] => sequence.Skip(index).First();
    }
}

extension은 수신기인 sequence을 정의하며, 이 수신기는 IEnumerable<int>입니다. 수신기 형식은 비제네릭, 개방형 제네릭 또는 닫힌 제네릭 형식일 수 있습니다. 이름은 sequence 해당 확장에 선언된 모든 인스턴스 멤버의 범위에 있습니다. 확장 메서드와 속성은 모두 sequence에 접근합니다.

확장 멤버는 수신기 유형의 멤버인 것처럼 액세스할 수 있습니다.

IEnumerable<int> numbers = Enumerable.Range(1, 10);
numbers = numbers.AddValue(10);

var median = numbers.Median;

동일한 수신기를 공유하는 한 단일 컨테이너에서 원하는 수의 멤버를 선언할 수 있습니다. 단일 클래스에서 확장 블록을 여러 개 선언할 수도 있습니다. 다른 확장은 수신기의 동일한 형식 또는 이름을 선언할 필요가 없습니다. 유일한 멤버가 정적인 경우 확장 매개 변수에 매개 변수 이름을 포함할 필요가 없습니다.

extension(IEnumerable<int>)
{
    // Method:
    public static IEnumerable<int> Generate(int low, int count, int increment)
    {
        for (int i = 0; i < count; i++)
            yield return low + (i * increment);
    }

    // Property:
    public static IEnumerable<int> Identity => Enumerable.Empty<int>();
}

정적 확장은 수신기 유형의 정적 멤버인 것처럼 호출할 수 있습니다.

var newSequence = IEnumerable<int>.Generate(5, 10, 2);
var identity = IEnumerable<int>.Identity;

중요합니다

확장은 멤버 선언에 대한 범위를 도입하지 않습니다. 단일 클래스에서 선언된 모든 멤버는 여러 확장에 있더라도 고유한 서명이 있어야 합니다. 생성된 서명에는 정적 멤버의 이름에 수신기 형식과 확장 인스턴스 멤버의 수신기 매개 변수가 포함됩니다.

다음 예제에서는 this 한정자를 사용한 확장 메서드를 보여줍니다.

public static class NumericSequenceExtensionMethods
{
    public static IEnumerable<int> AddValue(this IEnumerable<int> sequence, int operand)
    {
        foreach (var item in sequence)
            yield return item + operand;
    }
}

메서드는 Add 인터페이스의 IEnumerable<int> 멤버인 것처럼 다른 메서드에서 호출할 수 있습니다.

IEnumerable<int> numbers = Enumerable.Range(1, 10);
numbers = numbers.AddValue(10);

두 형태의 확장 메서드는 동일한 IL(중간 언어)을 생성합니다. 발신자는 둘을 구별할 수 없습니다. 실제로 호환성이 손상되는 변경 없이 기존 확장 메서드를 새 멤버 구문으로 변환할 수 있습니다. 형식들은 이진 형식과 소스 코드 모두와 호환됩니다.

일반 확장 블록

확장 블록에 선언된 확장 멤버에 대한 형식 매개 변수를 지정하는 위치는 해당 형식 매개 변수가 필요한 위치에 따라 달라집니다.

  • 형식 매개 변수가 수신기에서 사용될 때 extension 선언에 형식 매개 변수를 추가합니다.
  • 형식이 수신기에 지정된 형식 매개 변수와 다른 경우 멤버 선언에 형식 매개 변수를 추가합니다.
  • 두 위치 모두에서 동일한 형식 매개 변수를 지정할 수 없습니다.

다음 예제에서는 IEnumerable<T> 확장 블록의 멤버 중 두 개가 두 번째 형식 매개 변수를 필요로 하는 경우를 보여줍니다.

public static class GenericExtensions
{
    extension<TReceiver>(IEnumerable<TReceiver> source)
    {
        public IEnumerable<TReceiver> Spread(int start, int count)
            => source.Skip(start).Take(count);

        public IEnumerable<TReceiver> Append<TArg>(IEnumerable<TArg> second, Func<TArg, TReceiver> Converter)
        {
            foreach(TReceiver item in source)
            {
                yield return item;
            }
            foreach (TArg item in second)
            {
                yield return Converter(item);
            }
        }

        public IEnumerable<TReceiver> Prepend<TArg>(IEnumerable<TArg> second, Func<TArg, TReceiver> Converter)
        {
            foreach (TArg item in second)
            {
                yield return Converter(item);
            }
            foreach (TReceiver item in source)
            {
                yield return item;
            }
        }
    }
}

멤버 Append 를 지정하고 Prepend 변환에 대한 추가 형식 매개 변수를 지정합니다. 어떤 멤버도 수신기에 대한 형식 매개 변수를 반복하지 않습니다.

해당하는 확장 메서드 선언은 이러한 형식 매개 변수를 인코딩하는 방법을 보여 줍니다.

public static class GenericExtensions
{
    public static IEnumerable<T> Spread<T>(this IEnumerable<T> source, int start, int count)
        => source.Skip(start).Take(count);

    public static IEnumerable<T1> Append<T1, T2>(this IEnumerable<T1> source, IEnumerable<T2> second, Func<T2, T1> Converter)
    {
        foreach (T1 item in source)
        {
            yield return item;
        }
        foreach (T2 item in second)
        {
            yield return Converter(item);
        }
    }

    public static IEnumerable<T1> Prepend<T1, T2>(this IEnumerable<T1> source, IEnumerable<T2> second, Func<T2, T1> Converter)
    {
        foreach (T2 item in second)
        {
            yield return Converter(item);
        }
        foreach (T1 item in source)
        {
            yield return item;
        }
    }
}

참고하십시오

C# 언어 사양

자세한 내용은 C# 언어 사양을 참조하세요. 언어 사양은 C# 구문 및 사용의 최종 소스입니다.