컴파일 타임에 확장 메서드 바인딩

확장 메서드를 사용하여 클래스 또는 인터페이스를 확장할 수 있지만 재정의할 수는 없습니다. 
(확장 메소드 자체가 static 으로 정의됨)

이름과 시그니처가 인터페이스 또는 클래스 메서드와 동일한 확장 메서드는 호출되지 않습니다. 

컴파일 시간에 확장 메서드는 항상 형식 자체에서 정의된 인스턴스 메서드보다 우선 순위가 낮습니다. 

즉, 형식에 Process(int i)라는 메서드가 있고 동일한 시그니처를 가진 확장 메서드가 있는 경우 컴파일러는 항상 인스턴스 메서드에 바인딩합니다. 컴파일러는 메서드 호출을 발견할 경우 먼저 형식의 인스턴스 메서드에서 일치 항목을 찾습니다. 일치 항목이 없으면 형식에 대해 정의된 확장 메서드를 검색하고 찾은 첫 번째 확장 메서드에 바인딩합니다. 다음 예제에서는 컴파일러가 바인딩할 확장명 메서드 또는 인스턴스 메서드를 확인하는 방법을 보여 줍니다.

다음 예제에서는 C# 컴파일러가 메서드 호출을 형식의 인스턴스 메서드 또는 확장명 메서드에 바인딩할 것인지 결정할 때 따르는 규칙을 보여 줍니다. 정적 클래스 Extensions는 IMyInterface를 구현하는 모든 형식에 대해 정의된 확장 메서드를 포함합니다. AB및 C 클래스는 모두 인터페이스를 구현합니다.

MethodB 확장 메서드는 이름과 시그니처가 클래스에서 이미 구현된 메서드와 정확하게 일치하므로 호출되지 않습니다.

일치하는 시그니처를 가진 인스턴스 메서드를 찾을 수 없으면 컴파일러는 일치하는 확장명 메서드(있는 경우)에 바인딩합니다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// Define an interface named IMyInterface.
namespace DefineIMyInterface
{
    using System;
 
    public interface IMyInterface
    {
        // Any class that implements IMyInterface must define a method
        // that matches the following signature.
        void MethodB();
    }
}
 
 
// Define extension methods for IMyInterface.
namespace Extensions
{
    using System;
    using DefineIMyInterface;
 
    // The following extension methods can be accessed by instances of any 
    // class that implements IMyInterface.
    
    //확장 메소드를 만들기 위해선 확장 메소드가 포함되는 클래스에 static 을 붙여줘야 한다
    public static class Extension
    {
 
        //각각 IMyInterface 에 대한 확장 메소드 MethodA 에 대하여 정의한다
 
        //확장 메소드의 경우 this 가 붙는데 this 다음에 넘겨줄 타입을 정해줘야한다
        //확장 메소드 또한 오버로드가 가능하다
        public static void MethodA(this IMyInterface myInterface, int i)
        {
            Console.WriteLine("Extension.MethodA(this IMyInterface myInterface, int i)");
        }
 
        public static void MethodA(this IMyInterface myInterface, string s)
        {
            Console.WriteLine("Extension.MethodA(this IMyInterface myInterface, string s)");
        }
 
        //이 함수는 호출되지 않는데 왜냐면 각 A,B,C 3개 클래스는 시그니처에 매칭되는 MethodB를 구현하기 때문이다
        // This method is never called in ExtensionMethodsDemo1, because each 
        // of the three classes A, B, and C implements a method named MethodB
        // that has a matching signature.
        public static void MethodB(this IMyInterface myInterface)
        {
            Console.WriteLine("Extension.MethodB(this IMyInterface myInterface)");
        }
    }
}
 
 
// Define three classes that implement IMyInterface, and then use them to test
// the extension methods.
namespace ExtensionMethodsDemo1
{
    using System;
    using Extensions;
    using DefineIMyInterface;
 
    //각 클래스는 확장 메소드에 의해 확장된 IMyInterface 인터페이스를 상속 받는다
    class A : IMyInterface
    {
        public void MethodB() { Console.WriteLine("A.MethodB()"); }             //MethodB 구현 정의함
    }
 
    class B : IMyInterface
    {
        public void MethodB() { Console.WriteLine("B.MethodB()"); }             //MethodB 구현 정의함
        public void MethodA(int i) { Console.WriteLine("B.MethodA(int i)"); }
    }
 
    class C : IMyInterface
    {
        public void MethodB() { Console.WriteLine("C.MethodB()"); }             //MethodB 구현 정의함
        public void MethodA(object obj)
        {
            Console.WriteLine("C.MethodA(object obj)");
        }
    }
 
 
 
 
    public  class DemoClass
    {
        static void Main(string[] args)
        {
            // Declare an instance of class A, class B, and class C.
            // For a, b, and c, call the following methods:
            //      -- MethodA with an int argument
            //      -- MethodA with a string argument
            //      -- MethodB with no argument.
            //      
            A a = new A();
            B b = new B();
            C c = new C();
 
            
 
            // A contains no MethodA, so each call to MethodA resolves to 
            // the extension method that has a matching signature.
            a.MethodA(1);           // Extension.MethodA(IMyInterface, int)
            a.MethodA("hello");     // Extension.MethodA(IMyInterface, string)
 
            // A has a method that matches the signature of the following call
            // to MethodB.
            a.MethodB();            // A.MethodB()
 
            Console.WriteLine("");
 
            // B has methods that match the signatures of the following
            // method calls.
            b.MethodA(1);           // B.MethodA(int)
            b.MethodB();            // B.MethodB()
 
            // B has no matching method for the following call, but 
            // class Extension does.
            b.MethodA("hello");     // Extension.MethodA(IMyInterface, string)
 
 
            Console.WriteLine("");
 
 
            //C의 경우에는 확장 메소드MethodA가 있어도 C클래스에서 object 에 대한 함수를 정의해놨기 때문에
            //클래스(C)의 MethodA 가 호출되게 된다
            // C contains an instance method that matches each of the following
            // method calls.
            c.MethodA(1);           // C.MethodA(object)
            c.MethodA("hello");     // C.MethodA(object)
            c.MethodB();            // C.MethodB()
        }
    }
}
 

cs



결과


Extension.MethodA(this IMyInterface myInterface, int i)

Extension.MethodA(this IMyInterface myInterface, string s)

A.MethodB()


B.MethodA(int i)

B.MethodB()

Extension.MethodA(this IMyInterface myInterface, string s)


C.MethodA(object obj)

C.MethodA(object obj)

C.MethodB()



일반 지침

일반적으로 반드시 필요한 경우에만 드물게 확장 메서드를 구현하는 것이 좋습니다. 

가능하면 기존 형식을 확장해야 하는 클라이언트 코드는 기존 형식에서 파생된 새 형식을 만들어 이 작업을 수행해야 합니다. 
자세한 내용은 상속을 참조하세요.

기존 메서드를 사용하여 소스 코드를 변경할 수 없는 형식을 확장하는 경우 형식의 구현이 변경되어 확장명 메서드가 손상될 수도 있습니다.

지정된 형식에 대해 확장 메서드를 구현하는 경우 다음 사항에 유의하세요.

  • 시그니처가 형식에 정의된 메서드와 동일한 확장 메서드는 호출되지 않습니다.

  • 확장 메서드는 네임스페이스 수준에서 범위로 가져옵니다. 
    예를 들어 Extensions라는 단일 네임스페이스에 확장 메서드를 포함하는 여러 개의 정적 클래스가 있는 경우 using Extensions; 지시문을 통해 모두 범위로 가져옵니다.


구현된 클래스 라이브러리의 경우 어셈블리의 버전 번호가 증가되는 것을 방지하기 위해 확장 메서드를 사용해서는 안 됩니다. 소스 코드를 소유하고 있는 라이브러리에 중요 기능을 추가하려는 경우 어셈블리 버전 관리를 위한 표준 .NET Framework 지침을 따라야 합니다. 자세한 내용은 어셈블리 버전 관리를 참조하세요.



ref : https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/classes-and-structs/extension-methods



+ Recent posts