본문으로 바로가기

프로젝트를 수행하다 보면 구조적으로 다소 난해한 경우가 있습니다.다른개발자가 만들어 놓은 코드를 건드리기가 껄끄럽고, 사용용도와  빈도가 높지 않아 재사용성은 없지만 해당프로젝트에서만 유독 컨트롤로 사용되면서도 갯수는 많은 껄끄러운 작업의 경우가 그런 경우인데 이런 난감한 문제를 쉽게 해결하는 방법으로 확장 메소드(Extension Method)를 사용하면 깔끔하게 빠르게 처리할 수 있습니다.

이 항목에서는 .NET Framework 클래스 라이브러리 또는 확장 할 다른 .NET 형식의 모든 형식에 대해 고유 한 확장 메서드를 구현하는 방법을 보여줍니다 .
클라이언트 코드는 확장 메서드를 포함하는 DLL에 대한 참조를 추가 하고 확장 메서드가 정의 된 네임 스페이스를 지정 하는 using 지시문을 추가 하여 확장 메서드를 사용할 수 있습니다.
확장 메서드를 정의하고 호출하려면 확장 메서드를 포함 할 정적 클래스 를 정의합니다 .

호출 코드 에서 확장 메서드 클래스가 포함 된 네임 스페이스using 를 지정 하는 지시문을 추가합니다 .
메서드를 해당 형식의 인스턴스 메서드 인 것처럼 메서드를 호출합니다.
첫 번째 매개 변수는 연산자를 적용하는 유형을 나타내며 컴파일러가 이미 객체 유형을 알고 있으므로 호출 코드에서 지정하지 않습니다.

다음 예제 WordCount는 CustomExtensions.StringExtension클래스에 명명 된 확장 메서드를 구현합니다 .
이 메서드는 첫 번째 메서드 매개 변수로 지정된 String 클래스에서 작동합니다 .

CustomExtensions네임 스페이스는 응용 프로그램 네임 스페이스로 가져 및 방법은 내부에서 호출 Main하는 방법.

예를들어 아래의 코드의 경우

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
using System.Linq;
using System.Text;
using System;
namespace Extension_Methods_Simple
{
//Import the extension method namespace.
using CustomExtensions;
class Program
{
static void Main(string[] args)
{
string s = "The quick brown fox jumped over the lazy dog.";
int i = s.WordCount();
System.Console.WriteLine("Word count of s is {0}", i);
}
}
}

string s = “The quick brown fox jumped over the lazy dog.”;
int i = s.WordCount();
라고 되어 있는 부분을 살펴보면 String Class가 WordCount()라는 Method를 가지고 있지 않기 때문에 에러가 발생한다.

그런데 CustomExtensions 관련 코드를 추가하여 실행시켜보면 String 클래스에 WordCount()가 추가되어 동작하는 것과 같은 효과를 볼수 있다.

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
using System.Linq;
using System.Text;
using System;
namespace CustomExtensions
{
//Extension methods must be defined in a static class
public static class StringExtension
{
// This is the extension method.
// The first parameter takes the "this" modifier
// and specifies the type for which the method is defined.
public static int WordCount(this String str)
{
return str.Split(new char[] {' ', '.','?'}, StringSplitOptions.RemoveEmptyEntries).Length;
}
public static int WordCount(this int str)
{
            return 15;
}
}
}
namespace Extension_Methods_Simple
{
//Import the extension method namespace.
using CustomExtensions;
class Program
{
static void Main(string[] args)
{
  
 int i = s.WordCount();           
 System.Console.WriteLine("Word count of s is {0}", i);
 
 int v = 0;
 i = v.WordCount();//Onerloading
 System.Console.WriteLine("Word count of s is {0}", i);
}
}
}

위의 코드와 같이 사용하여 Method를 확장 할 수가 있습니다.
특정 Class또는 컨트롤에 필요한 기능을 추가 확장하여 쉽게 요구하는 기능을 구현 할 수 있으며, 프로젝트를 진행 할때 개발자가 사용하던 코드를 그대로 사용하면서 코드의 호환성을 유지 할 수있다는 장점이 있습니다.

다음의 간단한예제는 Form에 여러개의 Chart가 있다고 가정하고 어떤Chart는 Context Menu가 필요하고 또다른 Chart는 Context Menu가 필요없는 상황을 가정했을때 각각에 대해서 어떻게 처리하는것이 좋은지 보여주는 예제입니다.
먼저 Chart Extension을 작성합니다.

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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
 
namespace ChartExtension
{
    public static class ChrtListExtention
    {       
        public static void EnableContextMenu(this Chart chart)
        {
            chart.MouseDown += ChartControl_MouseDown;//마우스다운 이벤트 핸들러 등록
        }
 
        //// Context 메뉴 생성
        private static void ChartControl_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button != MouseButtons.Right) return;
            Chart chartGraph = (Chart)sender;
            if (chartGraph.ContextMenu == null)
            {
                MenuItem mnItm;
                ContextMenu contextMenu = new System.Windows.Forms.ContextMenu();
                ChartArea plots = chartGraph.ChartAreas[0];
             
                contextMenu.MenuItems.Add(mnItm = new MenuItem("Zoom-X", OnChartContext));
                mnItm.Checked = plots.CursorX.IsUserSelectionEnabled;
                contextMenu.MenuItems.Add(mnItm = new MenuItem("Zoom-Y", OnChartContext));
                mnItm.Checked = plots.CursorY.IsUserSelectionEnabled;               
                chartGraph.ContextMenu = contextMenu;
            }
 
        }
        ///
 
        /// Context Menu Click Action on Chart(메뉴에 대한 동작)
        
private static void OnChartContext(object sender, EventArgs e)
{
 ContextMenu menu = ((MenuItem)sender).GetContextMenu();
 Chart chartGraph = (Chart)menu.SourceControl;
 if (chartGraph.ChartAreas.Count <= 0) return;
 ChartArea plots = chartGraph.ChartAreas[0];
 MenuItem mmenuItm = (MenuItem)sender;//메뉴Item text
 switch (mmenuItm.Text)
{
 case "Zoom-X":
 {
  mmenuItm.Checked = !plots.CursorX.IsUserSelectionEnabled;
  plots.CursorX.IsUserSelectionEnabled = mmenuItm.Checked;
  }
 break;
 case "Zoom-Y":
 {
  mmenuItm.Checked = !plots.CursorY.IsUserSelectionEnabled;
 plots.CursorY.IsUserSelectionEnabled = mmenuItm.Checked;
 }
break;
}
}
 }
 }

외와 같이 Extension을 코딩한후
chart1.EnableContextMenu();
//chart2.EnableContextMenu();
chart3.EnableContextMenu();
와 같은 형태로 처리 하면 각각의 대상Chart에 대해서 조건문을 설정하거나,Chart 클래스를 상속해서  EnableContextMenu를 처리하지 않아도 됩니다.
각각의 Chart에 대한 Event를 처리하지 않아도 된다는 이점이 있을 뿐만 아니라, Chart에 모든 기능을 다 넣어 둘필요도, 프로젝트 상황에 따라 추가 상속 혹은 파생된 클래스를 무분별하게 만들어내는 불편함을 해소 할 수 있습니다.

또한 필요한 기능을 Class로 묶어 놓았기 때문에 재사용성도 높고 , 소스 관리의 효율성도 좋습니다, Form에서 Event를 받아서 처리할때에 비해서  훨씬 깔끔하게 코딩할 수 있습니다.

위으코드에서 Chart2는  EnableContextMenu()를 실행하지 않았기 때문에 Context메뉴는 동작 하지 않습니다.