다음을 통해 공유


방법: LINQ 쿼리용 사용자 지정 메서드 추가

IEnumerable<T> 인터페이스에 확장 메서드를 추가하여 LINQ 쿼리에 사용할 수 있는 메서드 집합을 확장할 수 있습니다.예를 들어, 일반적인 평균 또는 최대값 연산 외에도 값 시퀀스에서 단일 값을 계산하기 위해 사용자 지정 집계 메서드를 만들 수 있습니다.또한 값 시퀀스에 사용자 지정 필터나 특정 데이터 변환을 적용하고 새 시퀀스를 반환하는 메서드를 만들 수도 있습니다.이러한 메서드의 예로는 Distinct, Skip<TSource>Reverse<TSource>가 있습니다.

IEnumerable<T> 인터페이스를 확장하면 열거 가능한 모든 컬렉션에 사용자 지정 메서드를 적용할 수 있습니다.자세한 내용은 확장 메서드(C# 프로그래밍 가이드) 또는 확장 메서드(Visual Basic)를 참조하십시오.

집계 메서드 추가

집계 메서드는 값 집합에서 단일 값을 계산합니다.LINQ에서는 Average, MinMax를 비롯한 여러 가지 집계 메서드를 제공합니다.IEnumerable<T> 인터페이스에 확장 메서드를 추가하여 사용자 고유의 집계 메서드를 만들 수 있습니다.

다음 코드 예제에서는 Median이라는 확장 메서드를 만들어 double 형식의 숫자 시퀀스에 대한 중앙값을 계산하는 방법을 보여 줍니다.

Imports System.Runtime.CompilerServices

Module LINQExtension

    ' Extension method for the IEnumerable(of T) interface. 
    ' The method accepts only values of the Double type.
    <Extension()> 
    Function Median(ByVal source As IEnumerable(Of Double)) As Double
        If source.Count = 0 Then
            Throw New InvalidOperationException("Cannot compute median for an empty set.")
        End If

        Dim sortedSource = From number In source 
                           Order By number

        Dim itemIndex = sortedSource.Count \ 2

        If sortedSource.Count Mod 2 = 0 Then
            ' Even number of items in list.
            Return (sortedSource(itemIndex) + sortedSource(itemIndex - 1)) / 2
        Else
            ' Odd number of items in list.
            Return sortedSource(itemIndex)
        End If
    End Function
End Module
public static class LINQExtension
{
    public static double Median(this IEnumerable<double> source)
    {
        if (source.Count() == 0)
        {
            throw new InvalidOperationException("Cannot compute median for an empty set.");
        }

        var sortedList = from number in source
                         orderby number
                         select number;

        int itemIndex = (int)sortedList.Count() / 2;

        if (sortedList.Count() % 2 == 0)
        {
            // Even number of items.
            return (sortedList.ElementAt(itemIndex) + sortedList.ElementAt(itemIndex - 1)) / 2;
        }
        else
        {
            // Odd number of items.
            return sortedList.ElementAt(itemIndex);
        }
    }
}

열거 가능한 컬렉션에 대해 이 확장 메서드를 호출하는 방법은 IEnumerable<T> 인터페이스에서 다른 집계 메서드를 호출하는 방법과 같습니다.

[!참고]

Visual Basic에서는 Aggregate 또는 Group By 절에 메서드 호출이나 표준 쿼리 구문을 사용할 수 있습니다.자세한 내용은 Aggregate 절(Visual Basic)Group By 절(Visual Basic)을 참조하십시오.

다음 코드 예제에서는 double 형식의 배열에 Median 메서드를 사용하는 방법을 보여 줍니다.

        Dim numbers1() As Double = {1.9, 2, 8, 4, 5.7, 6, 7.2, 0}

        Dim query1 = Aggregate num In numbers1 Into Median()

        Console.WriteLine("Double: Median = " & query1)



...


        ' This code produces the following output:
        '
        ' Double: Median = 4.85

        double[] numbers1 = { 1.9, 2, 8, 4, 5.7, 6, 7.2, 0 };

        var query1 = numbers1.Median();

        Console.WriteLine("double: Median = " + query1);



...


/*
 This code produces the following output:

 Double: Median = 4.85
*/

Cc981895.collapse_all(ko-kr,VS.110).gif다양한 형식을 받아들이도록 집계 메서드 오버로드

다양한 형식의 시퀀스를 받아들이도록 집계 메서드를 오버로드할 수 있습니다.이렇게 하는 일반적인 방법은 각 형식에 대해 오버로드를 만드는 것입니다.또 다른 방법은 대리자를 사용하여 제네릭 형식을 받아들인 다음 특정 형식으로 변환하는 오버로드를 만드는 것입니다.두 방법을 함께 사용할 수도 있습니다.

Cc981895.collapse_all(ko-kr,VS.110).gif각 형식에 대해 오버로드를 만들려면

지원할 각 형식에 대해 특정 오버로드를 만들 수 있습니다.다음 코드 예제에서는 integer 형식에 대한 Median 메서드의 오버로드를 보여 줍니다.

' Integer overload

<Extension()> 
Function Median(ByVal source As IEnumerable(Of Integer)) As Double
    Return Aggregate num In source Select CDbl(num) Into med = Median()
End Function
//int overload

public static double Median(this IEnumerable<int> source)
{
    return (from num in source select (double)num).Median();
}

이제 다음 코드와 같이 integer 및 double 형식 둘 다에 대해 Median 오버로드를 호출할 수 있습니다.

        Dim numbers1() As Double = {1.9, 2, 8, 4, 5.7, 6, 7.2, 0}

        Dim query1 = Aggregate num In numbers1 Into Median()

        Console.WriteLine("Double: Median = " & query1)



...


        Dim numbers2() As Integer = {1, 2, 3, 4, 5}

        Dim query2 = Aggregate num In numbers2 Into Median()

        Console.WriteLine("Integer: Median = " & query2)



...


' This code produces the following output:
'
' Double: Median = 4.85
' Integer: Median = 3
        double[] numbers1 = { 1.9, 2, 8, 4, 5.7, 6, 7.2, 0 };

        var query1 = numbers1.Median();

        Console.WriteLine("double: Median = " + query1);



...


        int[] numbers2 = { 1, 2, 3, 4, 5 };

        var query2 = numbers2.Median();

        Console.WriteLine("int: Median = " + query2);



...


/*
 This code produces the following output:

 Double: Median = 4.85
 Integer: Median = 3
*/

Cc981895.collapse_all(ko-kr,VS.110).gif제네릭 오버로드를 만들려면

제네릭 개체의 시퀀스를 받아들이는 오버로드를 만들 수도 있습니다.이 오버로드는 대리자를 매개 변수로 사용하여 제네릭 형식 개체의 시퀀스를 특정 형식으로 변환할 수 있습니다.

다음 코드에서는 Func<T, TResult> 대리자를 매개 변수로 사용하는 Median 메서드의 오버로드를 보여 줍니다.이 대리자는 제네릭 형식 T의 개체를 받아들인 다음 double 형식의 개체를 반환합니다.

' Generic overload.

<Extension()> 
Function Median(Of T)(ByVal source As IEnumerable(Of T), 
                      ByVal selector As Func(Of T, Double)) As Double
    Return Aggregate num In source Select selector(num) Into med = Median()
End Function
// Generic overload.

public static double Median<T>(this IEnumerable<T> numbers,
                       Func<T, double> selector)
{
    return (from num in numbers select selector(num)).Median();
}

이제 원하는 형식 개체의 시퀀스에 대해 Median 메서드를 호출할 수 있습니다.해당 형식에 고유한 메서드 오버로드가 없을 경우 대리자 매개 변수를 전달해야 합니다.Visual Basic과 C#에서는 이를 위해 람다 식을 사용할 수 있습니다.또한 Visual Basic에서는 메서드 호출 대신 Aggregate 또는 Group By 절을 사용하는 경우 이 절의 범위에 있는 값이나 식을 전달할 수도 있습니다.

다음 코드 예제에서는 정수 배열과 문자열 배열에 대해 Median 메서드를 호출하는 방법을 보여 줍니다.문자열의 경우 배열에 있는 문자열의 길이에 대한 중앙값이 계산됩니다.이 예제에서는 각각의 경우에서 Median 메서드에 Func<T, TResult> 대리자 매개 변수를 전달하는 방법을 보여 줍니다.

Dim numbers3() As Integer = {1, 2, 3, 4, 5}

' You can use num as a parameter for the Median method 
' so that the compiler will implicitly convert its value to double.
' If there is no implicit conversion, the compiler will
' display an error message.

Dim query3 = Aggregate num In numbers3 Into Median(num)

Console.WriteLine("Integer: Median = " & query3)

Dim numbers4() As String = {"one", "two", "three", "four", "five"}

' With the generic overload, you can also use numeric properties of objects.

Dim query4 = Aggregate str In numbers4 Into Median(str.Length)

Console.WriteLine("String: Median = " & query4)

' This code produces the following output:
'
' Integer: Median = 3
' String: Median = 4
int[] numbers3 = { 1, 2, 3, 4, 5 };

/* 
  You can use the num=>num lambda expression as a parameter for the Median method 
  so that the compiler will implicitly convert its value to double.
  If there is no implicit conversion, the compiler will display an error message.          
*/

var query3 = numbers3.Median(num => num);

Console.WriteLine("int: Median = " + query3);

string[] numbers4 = { "one", "two", "three", "four", "five" };

// With the generic overload, you can also use numeric properties of objects.

var query4 = numbers4.Median(str => str.Length);

Console.WriteLine("String: Median = " + query4);

/*
 This code produces the following output:

 Integer: Median = 3
 String: Median = 4
*/

컬렉션을 반환하는 메서드 추가

값 시퀀스를 반환하는 사용자 지정 쿼리 메서드를 사용하여 IEnumerable<T> 인터페이스를 확장할 수 있습니다.이 경우 메서드는 IEnumerable<T> 형식의 컬렉션을 반환해야 합니다.이러한 메서드는 값 시퀀스에 필터나 데이터 변환을 적용하는 데 사용될 수 있습니다.

다음 예제에서는 첫 번째 요소부터 시작하여 컬렉션에 있는 요소를 하나씩 걸러서 반환하는 AlternateElements라는 확장 메서드를 만드는 방법을 보여 줍니다.

' Extension method for the IEnumerable(of T) interface. 
' The method returns every other element of a sequence.

<Extension()> 
Function AlternateElements(Of T)(
    ByVal source As IEnumerable(Of T)
    ) As IEnumerable(Of T)

    Dim list As New List(Of T)
    Dim i = 0
    For Each element In source
        If (i Mod 2 = 0) Then
            list.Add(element)
        End If
        i = i + 1
    Next
    Return list
End Function
// Extension method for the IEnumerable<T> interface. 
// The method returns every other element of a sequence.

public static IEnumerable<T> AlternateElements<T>(this IEnumerable<T> source)
{
    List<T> list = new List<T>();

    int i = 0;

    foreach (var element in source)
    {
        if (i % 2 == 0)
        {
            list.Add(element);
        }

        i++;
    }

    return list;
}

다음 코드와 같이 IEnumerable<T> 인터페이스에서 다른 메서드를 호출할 때와 같은 방법으로 열거 가능한 모든 컬렉션에 대해 이 확장 메서드를 호출할 수 있습니다.

Dim strings() As String = {"a", "b", "c", "d", "e"}

Dim query = strings.AlternateElements()

For Each element In query
    Console.WriteLine(element)
Next

' This code produces the following output:
'
' a
' c
' e
string[] strings = { "a", "b", "c", "d", "e" };

var query = strings.AlternateElements();

foreach (var element in query)
{
    Console.WriteLine(element);
}
/*
 This code produces the following output:

 a
 c
 e
*/

참고 항목

참조

IEnumerable<T>

확장 메서드(C# 프로그래밍 가이드)

개념

확장 메서드(Visual Basic)