확장 방법의 장점은 무엇입니까? [닫은]


84

C #의 "믿지 않는"사람이 확장 메서드의 목적이 무엇인지 물었습니다. 그런 다음 이미 정의 된 객체에 새 메서드를 추가 할 수 있다고 설명했습니다. 특히 원본 객체에 대한 소스를 소유 / 제어하지 않는 경우 더욱 그렇습니다.

그는 "왜 자신의 수업에 메소드를 추가하지 않습니까?" 우리는 (좋은 방식으로) 빙글 빙글 돌았습니다. 내 일반적인 반응은 이것이 도구 벨트의 또 다른 도구라는 것입니다. 그의 반응은 도구의 쓸모없는 낭비라는 것입니다. 그러나 나는 더 "깨달은"대답을 얻을 것이라고 생각했습니다.

자신의 클래스에 추가 된 메서드를 사용할 수 없었거나 사용해서는 안되는 확장 메서드를 사용한 몇 가지 시나리오는 무엇입니까?


2
사람들이 확장 메서드를 지원할 때 만들 수 있고 만들 수있는 유효한 포인트가 있다고 생각합니다. 그러나 확장 메서드 대신 정적 메서드를 사용하는 " 수 없었던 "시나리오 는 없습니다 . 확장 방법은 정말로 있는 다른 방법으로 접근 정적 인 방법. 명심해야 할 사항입니다.
Dan Tao

@DanTao, 가벼운 메모에서 확장 메서드로 호출을 대체 할 수 없게 만드는 한 가지는 바로 이름 지정입니다. Extensions.To(1, 10)무의미하고 1.To(10)설명 적입니다. 물론 나는 당신이 말하는 기술적 측면을 이해합니다. 사실 하나는 "시나리오가 없습니다 정적 방법, 예를 들어 반사 대신에 사용되는 확장 접근 방식을 가지고는"또 다른 경우이다 dynamic.
nawfal

답변:


35

확장 메서드는 코드를 작성할 때 많은 도움이된다고 생각합니다. 기본 유형에 확장 메서드를 추가하면 인텔리 센스에서 빠르게 얻을 수 있습니다.

파일 크기형식화 할 형식 공급자가 있습니다 . 그것을 사용하려면 다음과 같이 작성해야합니다.

Console.WriteLine(String.Format(new FileSizeFormatProvider(), "{0:fs}", fileSize));

다음과 같이 작성할 수있는 확장 메서드 만들기 :

Console.WriteLine(fileSize.ToFileSize());

더 깨끗하고 간단합니다.


4
확장 메서드에 대해 더 설명적인 이름을 사용하면 더 깔끔해집니다. 예 : fileSize.ToFormattedString ();
David Alpert

1
mmm, ToFormattedFizeSize () 아마도 Long 유형에 대한 확장 메서드 일 수 있습니다. ToFormattedString ()은 설명적인 이름이 아닙니다
Eduardo Campañó

3
그래도 포인트가 만들어졌습니다. fileSize.ToFileSize ()를 읽을 때 복제 이유를 묻습니다. 실제로 무엇을하고 있습니까? 나는 그것이 단지 예일 뿐이라는 것을 알고 있지만 설명적인 이름은 그것을 깨끗하고 간단하게 만드는 데 도움이됩니다.
David Alpert

1
테스트와 마찬가지로 올바른 이름을 선택하는 것이 매우 중요합니다.
Eduardo Campañó

5
그러나 제공 한 예제가 확장 메서드 일 필요가 없기 때문에 실제로 질문에 직접 대답하는 것은 아닙니다. 당신은을 가질 수 있었는데 LongToFileSize(fileSize), 이는 똑같이 간결하고 분명합니다.
Dan Tao

83

확장 메서드 의 유일한 장점은 코드 가독성입니다. 그게 다야.

확장 메서드를 사용하면 다음을 수행 할 수 있습니다.

foo.bar();

대신 :

Util.bar(foo);

이제 C #에는 이와 같은 많은 것들이 있습니다. 즉, C #에는 사소 해 보이고 그 자체로는 큰 이점이없는 많은 기능이 있습니다. 그러나 이러한 기능을 함께 결합하기 시작하면 부분의 합보다 조금 더 큰 것을 보게됩니다. 확장 메서드가 없으면 LINQ 쿼리를 거의 읽을 수 없으므로 LINQ는 확장 메서드의 이점을 크게 얻습니다. LINQ는 확장 메서드 없이는 가능 하지만 실용적이지는 않습니다.

확장 메서드는 C #의 부분 클래스와 매우 유사합니다. 그 자체로는별로 도움이되지 않고 사소 해 보입니다. 그러나 생성 된 코드가 필요한 클래스로 작업을 시작하면 부분 클래스가 훨씬 더 이해되기 시작합니다.


1
이것은 x.Foo (something) .Bar (somethingelse) .Baz (yetmoresomething)과 같은 체인 메서드를 사용하는 경우 더욱 중요합니다. 이것은 IEnumerable <> 확장 메서드에서 가장 널리 퍼져 있으며 가독성을 크게 향상시킵니다
ShuggyCoUk

2
내가 이해하지 못하는 것은 foo.bar ()가 나에게 bar ()가 foo의 메소드라고 제안한다는 것입니다. 그래서 그것이 작동하지 않을 때 나는 결국 잘못된 곳을 찾게됩니다. 이것이 실제로 나에게 가독성 향상인지 확실하지 않습니다.
Martin Brown

3
VS IDE에서 bar ()를 마우스 오른쪽 버튼으로 클릭하고 정의로 이동을 선택하면 올바른 위치로 이동합니다.
Jeff Martin

9
98 %의 언어 구조의 유일한 장점은 코드 가독성입니다. 분기 연산자, 레이블, 이동 및 증분을 넘어서는 모든 것이 삶을 좀 더 쉽게 만들어줍니다.
Giovanni Galbo

2
그것은 전적으로 사실이 아니며 확장 메서드가 클래스를 확장하는 유일한 방법 인 경우가 있습니다. 봉인 된 수업 외에 나는 그것들을 매우 독특한 상황에서 사용합니다. 아래 내 게시물을 참조하십시오.
Edwin Jarvis

34

툴링을 잊지 마세요! Foo 유형에 확장 메서드 M을 추가하면 Foo의 인텔리 센스 목록에 'M'이 표시됩니다 (확장 클래스가 범위 내에 있다고 가정). 이렇게하면 MyClass.M (Foo, ...)보다 'M'을 훨씬 쉽게 찾을 수 있습니다.

하루가 끝나면 다른 정적 방법에 대한 통사론 적 설탕이지만 집을 사는 것과 같습니다 : '위치, 위치, 위치!' 유형에 매달리면 사람들이 찾을 것입니다!


2
이것에도 약간의 부정적인 점이 있습니다. 확장 메서드 (예 : System.Linq의 확장 메서드는 IntelliSense 자동 완성을 더 긴 목록으로 채우므로 탐색하기가 조금 더 어려워집니다.
Jared Updike

@Jared : ...하지만 확장 메서드가있는 네임 스페이스를 가져온 경우에만 실제로이 "IntelliSense 오염"을 약간 제어 할 수 있습니다. 둘째, BCL String에는 상당히 긴 인스턴스 메서드 목록과 함께 제공되는 클래스 (예 :)가 있으므로이 문제는 확장 메서드에만 국한되지 않습니다.
stakx-더 이상 기여하지 않음

29

내가 본 확장 방법의 두 가지 추가 이점 :

  • 유창한 인터페이스는 확장 메서드의 정적 클래스로 캡슐화 될 수 있으므로 핵심 클래스와 유창한 확장 간의 문제를 분리 할 수 ​​있습니다. 나는 더 큰 유지 보수를 달성하는 것을 보았습니다.
  • 확장 메서드는 인터페이스에서 중단 될 수 있으므로 컨트랙트 (인터페이스를 통해) 및 연관된 일련의 인터페이스 기반 동작 (확장 메서드를 통해)을 지정할 수 있으며 다시 우려 사항을 분리 할 수 ​​있습니다. 일례의 방법은 원하는 Linq에 연장되어 Select(...), Where(...)오프 등 기형 IEnumerable<T>인터페이스.

1
더 잘 이해할 수 있도록 두 가지 요점에 대한 코드 예제를 인용 해 주시겠습니까? 흥미로운 관점 인 것 같습니다.
RBT

네, 두 번째 포인트에 대한 예가 좋을 것입니다.
Ini

26

확장 메서드에 대한 가장 좋은 용도 중 일부는 다음과 같은 기능입니다.

  1. 타사 개체의 기능을 확장합니다 (상업적이든 회사 내부이든 별도의 그룹에 의해 관리 됨). 대부분의 경우 sealed.
  2. 추상 클래스를 구현할 필요없이 인터페이스에 대한 기본 기능 생성

예를 들어, IEnumerable<T>. 확장 메서드가 풍부하지만 일반적인 ForEach 메서드를 구현하지 않은 것이 귀찮습니다. 그래서 나는 내 자신을 만들었습니다.

public void ForEach<T>(this IEnumerable<T> enumerable, Action<T> action)
{
    foreach ( var o in enumerable )
    {
        action(o);
    }
}

Voila, IEnumerable<T>구현 유형에 관계없이 모든 객체, 내가 작성했는지 여부와 관계없이 이제 ForEach코드에 적절한 "using"문을 추가하여 메서드를 갖게 되었습니다.


3
+1이 확장 프로그램이 마음에 들었습니다. 매우 유용합니다
Maslow

10
메서드는 정적이어야합니다. 이 확장을 사용하기로 결정하기 전에 blogs.msdn.com/ericlippert/archive/2009/05/18/… 을 읽는 것이 좋습니다 .
TrueWill

IEnumerable에서 ForEach 확장 메서드를 구현하는 것이 좋지 않은 이유 -blogs.msdn.microsoft.com/ericlippert/2009/05/18/…
RBT

12

확장 메서드를 사용하는 가장 큰 이유 중 하나는 LINQ입니다. 확장 메서드가 없으면 LINQ에서 할 수있는 많은 작업이 매우 어려울 것입니다. Where (), Contains (), Select 확장 메서드는 구조를 변경하지 않고 기존 유형에 훨씬 더 많은 기능이 추가됨을 의미합니다.


4
그것의 '하나'가 아니라 확장 방법의 이유입니다.
gbjbaanb

3
어떻게? 확장 방법을 사용하는 여러 이유 중 하나이며 유일한 요구 사항은 아닙니다. LINQ를 사용하지 않고 확장 메서드를 사용할 수 있습니다.
Ray Booysen 2010

나는 그가 그것이 창조 된 이유라고 생각한다고 생각하지만, 그렇습니다.
Brent Rittenhouse

9

확장 방법 의 장점 에 대한 많은 답변이 있습니다 . 단점을 해결하는 방법은 어떻습니까?

가장 큰 단점은 동일한 컨텍스트에서 동일한 서명을 가진 일반 메서드와 확장 메서드가있는 경우 컴파일러 오류나 경고가 없다는 것입니다.

특정 클래스에 적용되는 확장 메서드를 생성한다고 가정합니다. 그런 다음 나중에 누군가 해당 클래스 자체에 동일한 서명을 가진 메서드를 만듭니다.

코드가 컴파일되고 런타임 오류가 발생하지 않을 수도 있습니다. 그러나 더 이상 이전과 동일한 코드를 실행하지 않습니다.


1
4. 소유하지 않은 유형을 확장하기 전에 두 번 생각하십시오 . 소유 한 유형에 대한 확장 메서드 만 작성하면 확장중인 유형의 변경으로 인해 확장이 손상되는 것에 대해 걱정할 필요가 없습니다. 다른 한편으로, 당신이 본질적으로 그들의 자비에 달려있는 것보다 다른 사람들 유형을 확장하는 경우.
DavidRR

1
... 또는 다른 사람이 사용할 가능성이없는 이름을 선택하거나 정의하는 총 확장 방법 수를 최소화하여 (예 : 표면적 감소) 이러한 위험을 최소화 할 수 있습니다. 이를 수행하는 한 가지 기술은 기본 개체를 사용자가 제어하는 ​​다른 형식으로 변환하는 하나의 확장 메서드를 작성하는 것입니다.
DavidRR

확장 메서드 (C # 프로그래밍 가이드) : 일반적으로 확장 메서드를 직접 구현하는 것보다 훨씬 더 자주 호출하게됩니다.
DavidRR


4

Extension 메서드에 대한 개인적인 주장은 OOP 디자인에 매우 적합하다는 것입니다. 간단한 방법을 고려하십시오.

bool empty = String.IsNullOrEmpty (myString)

비교해서

bool empty = myString.IsNullOrEmpty ();

나는 당신의 예제가 OOP와 어떤 관련이 있는지 알지 못합니다. 무슨 말이야?
Andrew Hare

1
메서드가 객체에 속하는 것으로 "보인다"
Bluenuance

3
이것은 나쁜 예이지만 (NullReferenceException을 던질 수 있음) 그는 올바른 길을 가고 있습니다. 더 나은 예는 Math.abs (-4)를 -4.abs ();
Outlaw Programmer

15
내 지식과 내 경험에 비추어 볼 때 메모리가 제공되는 경우 myString.IsNullOrEmpty ()는 확장 메서드가 실행하기 위해 개체 인스턴스를 필요로하지 않기 때문에 NullReferenceException을 throw 할 필요가 없습니다.
David Alpert

1
저는 개인적으로 null 인스턴스와 함께 작동하도록 의도 된 확장 메서드의 팬이 아닙니다. 독자에게는 하나처럼 보이지만 다른 작업을 수행합니다.
Mark Simpson

4

위의 확장 메서드를 사용하여 수행 할 수있는 훌륭한 답변이 많이 있습니다.

내 짧은 대답은-그들은 공장에 대한 필요성을 거의 제거합니다.

나는 그것들이 새로운 개념이 아니라는 점을 지적 할 것이며 이들의 가장 큰 유효성 중 하나는 Objective-C ( 카테고리 ) 의 킬러 기능이라는 것 입니다. NeXT는 NSA와 월스트리트 금융 모델러를 주요 사용자로 보유 할 정도로 프레임 워크 기반 개발에 많은 유연성을 추가합니다.

REALbasic은 또한 그것들을 extends 메소드 로 구현하며 개발을 단순화하는 유사한 용도로 사용되었습니다.


4

확장 메서드의 중요한 이유로 향상된 코드 가독성을 언급하는 다른 답변을 지원하고 싶습니다. 이 두 가지 측면, 즉 메서드 체인과 중첩 된 메서드 호출, 그리고 의미없는 정적 클래스 이름을 가진 LINQ 쿼리의 복잡함으로이를 설명하겠습니다.


이 LINQ 쿼리를 예로 들어 보겠습니다.

numbers.Where(x => x > 0).Select(x => -x)

Where및 둘 다 Select정적 클래스에 정의 된 확장 메서드 Enumerable입니다. 따라서 확장 메서드가 존재하지 않고 이것이 일반적인 정적 메서드라면 코드의 마지막 줄은 본질적으로 다음과 같아야합니다.

Enumerable.Select(Enumerable.Where(numbers, x => x > 0), x => -x)

그 쿼리가 방금 얼마나 나빠 졌는지 확인하십시오.


둘째, 이제 고유 한 쿼리 연산자를 도입하려는 경우 프레임 워크에 있고 해당 클래스를 제어 할 수 없기 Enumerable때문에 다른 모든 표준 쿼리 연산자처럼 정적 클래스 내에서 정의 할 방법이 당연히 없습니다 Enumerable. 따라서 확장 메서드를 포함하는 고유 한 정적 클래스를 정의해야합니다. 그런 다음 다음과 같은 쿼리를 얻을 수 있습니다.

Enumerable.Select(MyEnumerableExtensions.RemoveNegativeNumbers(numbers), x => -x)
//                ^^^^^^^^^^^^^^^^^^^^^^
//                different class name that has zero informational value
//                and, as with 'Enumerable.xxxxxx', only obstructs the
//                query's actual meaning.

3

(확장) 메서드를 클래스에 직접 추가 할 수 있다는 것은 사실입니다. 그러나 모든 수업이 당신에 의해 작성되는 것은 아닙니다. 핵심 라이브러리 또는 타사 라이브러리의 클래스는 종종 닫히고 확장 메서드 없이는 구문 적 설탕을 얻을 수 없습니다. 그러나 확장 메서드는 예를 들어 (정적) 독립형 메서드와 같습니다. C ++


3

확장 메서드는 클래스 및 클래스 종속성을 깨끗하게 유지하는데도 도움이됩니다. 예를 들어, Foo가 사용되는 모든 곳에서 Foo 클래스에 대한 Bar () 메서드가 필요할 수 있습니다. 그러나 다른 어셈블리에 해당 어셈블리에만 .ToXml () 메서드가 필요할 수 있습니다. 이 경우 원본 어셈블리가 아닌 해당 어셈블리에 필요한 System.Xml 및 / 또는 System.Xml.Linq 종속성을 추가 할 수 있습니다.

이점 : 정의하는 클래스 어셈블리의 종속성이 필수 사항으로 만 줄어들고 다른 소비 어셈블리는 ToXml () 메서드를 사용하지 못하게됩니다. 자세한 내용은 이 PDC 프레젠테이션 을 참조하십시오.


3

확장 메서드가 코드의 가독성을 높이는 데 동의하지만 실제로는 정적 도우미 메서드에 불과합니다.

클래스에 동작을 추가하기 위해 확장 메서드를 사용하는 IMO는 다음과 같습니다.

혼란 스러움 : 프로그래머는 메서드가 확장 유형의 일부라고 생각할 수 있으므로 확장 네임 스페이스를 가져 오지 않을 때 메서드가 사라진 이유를 이해하지 못할 수 있습니다.

반 패턴 : 확장 메서드를 사용하여 프레임 워크의 유형에 동작을 추가 한 다음 단위 테스트를 수행하는 사람에게 전달하기로 결정합니다. 이제 그는 자신이 속일 수없는 많은 메소드를 포함하는 프레임 워크를 가지고 있습니다.


개발자가 속일 수없는 많은 방법에 갇혀있는 것은 사실이 아닙니다. 이러한 확장 메서드는 결국 확장중인 클래스 / 인터페이스에서 일부 메서드를 호출하며이 메서드는 가상이라는 점에서 가로 챌 수 있습니다.
Patrik Hägne 2010

1
음, 확장 방법에서 수행되는 작업에 따라 다릅니다. 인터페이스에서 제공된 확장 메소드를 사용하지만 확장 메소드라는 것을 알지 못한다고 가정 해 보겠습니다. 그런 다음 인터페이스에 대한 메서드 호출을 가짜로 만들고 싶지는 않지만 실제로 정적 메서드를 호출하고 있다는 것을 알게됩니다. 정적 메서드 호출은 프록시 기반 위조 API에 의해 가로 챌 수 없으므로 유일한 옵션은 확장 메서드를 반영하여 실제로 위조 할 메서드를 찾는 것입니다. 단위 테스트 IMO와 결합하면 여전히 반 패턴입니다.
HaraldV 2011 년

2

확장 메서드는 실제로 Martin Fowler의 책 (메서드 서명까지) 의 "Introduce Foreign Method" 리팩터링 의 .NET 통합입니다 . 기본적으로 동일한 이점과 함정이 있습니다. 이 리팩터링에 대한 섹션에서 그는 메서드를 실제로 소유해야하는 클래스를 수정할 수없는 경우에 대한 해결 방법이라고 말합니다.


2
+1하지만 인터페이스와 함께 확장 메서드를 사용할 수도 있습니다.
TrueWill

2

나는 주로 확장 방법이 무료 기능을 허용하지 않아야한다는 인정으로 봅니다.

C ++ 커뮤니티에서는 멤버보다 무료 비 멤버 함수를 선호하는 것이 좋은 OOP 관행으로 간주되는 경우가 많습니다. 이러한 함수는 필요하지 않은 개인 멤버에 대한 액세스 권한을 얻음으로써 캡슐화를 깨지 않기 때문입니다. 확장 방법은 동일한 작업을 수행하는 원형 교차로처럼 보입니다. 즉, private 멤버에 액세스 할 수없는 정적 함수에 대한 더 깨끗한 구문입니다.

확장 방법은 통사론 적 설탕에 지나지 않지만 사용하는 데 아무런 해가 없습니다.


2
  • 추악한 유틸리티 함수를 호출하는 대신 개체 자체에 대한 Intellisense
  • 변환 함수의 경우 "XToY (X x)"를 "ToY (this X x)"로 변경하면 추악한 XToY (x) 대신 예쁜 x.ToY ()가 생성됩니다.
  • 제어 할 수없는 클래스 확장
  • 클래스 자체에 메서드를 추가하는 것이 바람직하지 않은 경우 클래스의 기능을 확장합니다. 예를 들어, 비즈니스 객체를 단순하고 논리가없는 상태로 유지하고 확장 메서드에 추악한 종속성이있는 특정 비즈니스 논리를 추가 할 수 있습니다.

2

객체 모델 클래스를 재사용하는 데 사용합니다. 데이터베이스에있는 개체를 나타내는 클래스가 많이 있습니다. 이러한 클래스는 클라이언트 측에서만 개체를 ​​표시하는 데 사용되므로 기본 용도는 속성에 액세스합니다.

public class Stock {
   public Code { get; private set; }
   public Name { get; private set; }
}

이러한 사용 패턴 때문에 이러한 클래스에 비즈니스 논리 메서드를 포함하고 싶지 않으므로 모든 비즈니스 논리를 확장 메서드로 만듭니다.

public static class StockExtender {
    public static List <Quote> GetQuotesByDate(this Stock s, DateTime date)
    {...}
}

이렇게하면 불필요한 코드로 클라이언트 측에 과부하를주지 않고 비즈니스 로직 처리 및 사용자 인터페이스 표시에 동일한 클래스를 사용할 수 있습니다.

이 솔루션에 대한 한 가지 흥미로운 점은 내 개체 모델 클래스가 Mono.Cecil을 사용하여 동적으로 생성 된다는 것이므로 원하는 경우에도 비즈니스 논리 메서드를 추가하기가 매우 어려울 것입니다. XML 정의 파일을 읽고 데이터베이스에있는 일부 개체를 나타내는 이러한 스텁 클래스를 생성하는 컴파일러가 있습니다. 이 경우 유일한 방법은 확장하는 것입니다.


1
이를 위해 부분 클래스를 사용할 수 있습니다 ...
JJoos 2010


1

마지막 프로젝트에서는 확장 메서드를 사용하여 Validate () 메서드를 비즈니스 개체에 연결했습니다. 직렬화 가능한 데이터 전송 개체가있는 비즈니스 개체가 제품, 고객, 판매자 등과 같은 일반 전자 상거래 엔티티가있는 다른 도메인에서 사용될 것이기 때문에 이것을 정당화했습니다. 다른 도메인에서는 비즈니스 규칙도 다를 수 있으므로 내 캡슐화했습니다. 내 데이터 전송 개체의 기본 클래스에 추가 된 Validate 메서드의 늦은 바인딩 유효성 검사 논리. 이것이 의미가 있기를 바랍니다 :)


1

확장 방법이 매우 유용한 한 가지 사례는 ASMX 웹 서비스를 사용하는 클라이언트 응용 프로그램에서였습니다. 직렬화로 인해 웹 메서드의 반환 유형에는 메서드가 포함되지 않습니다 (이러한 유형의 공용 속성 만 클라이언트에서 사용할 수 있음).

확장 메서드를 사용하면 클라이언트 쪽에서 또 다른 개체 모델이나 수많은 래퍼 클래스를 만들지 않고도 웹 메서드에서 반환 된 형식에 기능 (클라이언트 쪽)을 추가 할 수 있습니다.


1

확장 메서드는 C #에서 일종의 믹스 인 을 만드는 데 사용할 수 있습니다 .

이것은 차례로 직교 개념에 대한 관심사를 더 잘 분리합니다. 이 답변 을 예로 들어보십시오.

이것은 또한 DCI 아키텍처의 중심 개념 인 C #에서 역할 을 활성화하는 데 사용할 수 있습니다 .


1

또한 확장 메서드가 C # 스타일로 사용될 때 Linq 쿼리를 더 쉽게 읽을 수 있도록 지원하는 방법으로 추가되었습니다.

이 두 가지 영향은 절대적으로 동일하지만 첫 번째는 훨씬 더 읽기 쉽습니다 (물론 더 많은 메서드를 연결하면 가독성의 격차가 증가합니다).

int n1 = new List<int> {1,2,3}.Where(i => i % 2 != 0).Last();

int n2 = Enumerable.Last(Enumerable.Where(new List<int> {1,2,3}, i => i % 2 != 0));

정규화 된 구문은 다음과 같아야합니다.

int n1 = new List<int> {1,2,3}.Where<int>(i => i % 2 != 0).Last<int>();

int n2 = Enumerable.Last<int>(Enumerable.Where<int>(new List<int> {1,2,3}, i => i % 2 != 0));

우연히, Where및 의 유형 매개 Last변수는이 두 메소드의 첫 번째 매개 변수 (키워드에 의해 도입되어 this확장 메소드로 만드는 매개 변수)의 존재 덕분에 추론 될 수 있으므로 명시 적으로 언급 할 필요가 없습니다 .

이 점은 분명히 확장 메서드의 장점이며 메서드 체인이 관련된 모든 유사한 시나리오에서 이점을 얻을 수 있습니다.

특히, 어떤 서브 클래스에서든 기본 클래스 메서드를 호출 할 수 있고이 서브 클래스에 대한 강력한 형식의 참조 (서브 클래스 형식 사용)를 반환하는 것이 더 우아하고 설득력있는 방법입니다.

예 (좋아,이 시나리오는 완전히 치즈 맛이 없다) : 좋은 밤을 보낸 후 동물이 눈을 뜨고 울음을 터뜨린다. 모든 동물은 똑같은 방식으로 눈을 뜨고 개는 짖고 오리는 삑삑 거리는 소리를냅니다.

public abstract class Animal
{
    //some code common to all animals
}

public static class AnimalExtension
{
    public static TAnimal OpenTheEyes<TAnimal>(this TAnimal animal) where TAnimal : Animal
    {
        //Some code to flutter one's eyelashes and then open wide
        return animal; //returning a self reference to allow method chaining
    }
}

public class Dog : Animal
{
    public void Bark() { /* ... */ }
}

public class Duck : Animal
{
    public void Kwak() { /* ... */ }
}

class Program
{
    static void Main(string[] args)
    {
        Dog Goofy = new Dog();
        Duck Donald = new Duck();
        Goofy.OpenTheEyes().Bark(); //*1
        Donald.OpenTheEyes().Kwak(); //*2
    }
}

개념적 OpenTheEyes으로는 Animal메서드 여야 하지만 그런 다음 Animal특정 하위 클래스 메서드와 같은 Bark또는 기타를 알지 못하는 추상 클래스의 인스턴스를 반환합니다 Duck. * 1 및 * 2로 주석 처리 된 두 줄은 컴파일 오류를 발생시킵니다.

그러나 확장 메서드 덕분에 "호출되는 하위 클래스 유형을 알고있는 기본 메서드"와 같은 종류를 가질 수 있습니다.

간단한 제네릭 메서드로 작업을 수행 할 수 있지만 훨씬 더 어색한 방식으로 수행 할 수 있습니다.

public abstract class Animal
{
    //some code common to all animals

    public TAnimal OpenTheEyes<TAnimal>() where TAnimal : Animal
    {
        //Some code to flutter one's eyelashes and then open wide
        return (TAnimal)this; //returning a self reference to allow method chaining
    }
}

이번에는 매개 변수가 없으므로 반환 유형 추론이 불가능합니다. 호출은 다음과 같을 수 있습니다.

Goofy.OpenTheEyes<Dog>().Bark();
Donald.OpenTheEyes<Duck>().Kwak();

... 더 많은 체이닝이 포함되면 코드의 무게를 많이 측정 할 수 있습니다 (특히 유형 매개 변수가 항상 <Dog>Goofy의 라인과 <Duck>Donald의 라인에 있음을 알고 ...)


1
처음으로 "kwak"을 본 적이 있습니다. 이것은 다른 나라에서 흔한 철자입니까? 철자를 본 유일한 방법은 "돌팔이"입니다.
Brent Rittenhouse

0

나는 그것에 대해 말할 단 한 단어 만 가지고 있습니다. 유지 관리 이것은 확장 방법 사용의 핵심입니다.


4
이게 무슨 뜻인지 이해가 안 돼서 한 단어 이상이 필요할 것 같아요.
Outlaw Programmer

2
나는 실제로 그것이 확장 방법 대한 논쟁이라고 말할 것입니다 . 확장 방법의 위험 중 하나는 모든 사람이 만들 수있는 모든 곳에있을 수 있다는 것입니다. 조심스럽게 사용하지 않으면 야생 성장이 발생할 수 있습니다.
Boris Callens

EM을 사용할 때 모든 참조를 쉽게 찾을 수 있습니다. 또한 한 가지 방법을 전역 적으로 변경하려면 한 곳에서만 수행 할 수 있습니다
Tamir

0

확장 메서드가 더 명확한 코드를 작성하는 데 도움이된다고 생각합니다.

친구가 제안한 것처럼 클래스에 새 메서드를 넣는 대신 ExtensionMethods 네임 스페이스에 넣습니다. 이런 식으로 수업에 논리적 질서를 유지합니다. 클래스를 실제로 직접 처리하지 않는 메서드는이를 복잡하게 만들지 않습니다.

확장 메서드가 코드를 더 명확하고 적절하게 구성한다고 생각합니다.


0

편집자 / IDE가 자동 완성 제안을 스마트하게 수행 할 수 있습니다.


0

나는 HTML을 구축하기 위해 그들을 좋아합니다. 자주 반복적으로 사용되거나 함수가 유용하지만 프로그램의 흐름을 깨뜨리는 반복적으로 생성되는 섹션이 있습니다.

        HTML_Out.Append("<ul>");
        foreach (var i in items)
            if (i.Description != "")
            {
                HTML_Out.Append("<li>")
                    .AppendAnchor(new string[]{ urlRoot, i.Description_Norm }, i.Description)
                    .Append("<div>")
                    .AppendImage(iconDir, i.Icon, i.Description)
                    .Append(i.Categories.ToHTML(i.Description_Norm, urlRoot)).Append("</div></li>");
            }

        return HTML_Out.Append("</ul>").ToString();

HTML 출력 확장 메서드를 사용하여 클래스 내에서 프레젠테이션과 논리를 혼합하지 않고도이 기능을 추가 할 수 있도록 개체에 사용자 지정 논리를 준비해야하는 상황도 있습니다.


0

확장 메서드가 중첩 된 제네릭 인수를 일치시키는 데 유용하다는 것을 알았습니다.

좀 이상하게 들리지만 제네릭 클래스 MyGenericClass<TList>가 있고 TList 자체가 제네릭 (예 : a List<T>) 이라는 것을 알고 있습니다. 두 확장없이 List에서 중첩 된 'T'를 찾아 낼 방법이 없다고 생각합니다. 메서드 또는 정적 도우미 메서드. 우리가 처리 할 수있는 정적 도우미 메서드 만 있으면 (a)보기 흉하고 (b) 클래스에 속한 기능을 외부 위치로 이동하도록 강제합니다.

예를 들어 튜플의 유형을 검색하고이를 메소드 서명으로 변환하려면 확장 메소드를 사용할 수 있습니다.

public class Tuple { }
public class Tuple<T0> : Tuple { }
public class Tuple<T0, T1> : Tuple<T0> { }

public class Caller<TTuple> where TTuple : Tuple { /* ... */ }

public static class CallerExtensions
{
     public static void Call<T0>(this Caller<Tuple<T0>> caller, T0 p0) { /* ... */ }

     public static void Call<T0, T1>(this Caller<Tuple<T0, T1>> caller, T0 p0, T1 p1) { /* ... */ }
}

new Caller<Tuple<int>>().Call(10);
new Caller<Tuple<string, int>>().Call("Hello", 10);

즉, 구분선이 어디에 있어야하는지 잘 모르겠습니다. 언제 메서드가 확장 메서드 여야하고 언제 정적 도우미 메서드 여야합니까? 이견있는 사람?


0

내 화면에 입력 영역이 있고 모두 정확한 유형 (텍스트 상자, 확인란 등)이 무엇이든 표준 동작을 구현해야합니다. 각 입력 영역 유형이 이미 특정 클래스 (TextInputBox 등)에서 파생되므로 공통 기본 클래스를 상속 할 수 없습니다.

상속 계층 구조로 올라가면 WebControl과 같은 공통 조상을 찾을 수 있지만 프레임 워크 클래스 WebControl을 개발하지 않았고 필요한 것을 노출하지도 않았습니다.

확장 방법을 사용하면 다음을 수행 할 수 있습니다.

1) WebControl 클래스를 확장 한 다음 모든 입력 클래스에서 통합 된 표준 동작을 얻습니다.

2) 또는 IInputZone과 같은 인터페이스에서 모든 클래스를 파생시키고이 인터페이스를 메서드로 확장합니다. 이제 모든 입력 영역에서 인터페이스와 관련된 확장 메서드를 호출 할 수 있습니다. 따라서 입력 영역이 이미 여러 기본 클래스에서 파생 되었기 때문에 일종의 다중 상속을 달성했습니다.


0

특히 위에 게시 된 IEnumerables에는 확장 메서드의 훌륭한 예가 너무 많습니다.

예를 들어 IEnumerable<myObject>I can create and extension method forIEnumerable<myObject>

mylist List<myObject>;

... 목록 만들기

mylist.DisplayInMyWay();

확장 메서드가 없으면 다음을 호출해야합니다.

myDisplayMethod(myOldArray); // can create more nexted brackets.

또 다른 좋은 예는 순식간에 순환 연결 목록을 만드는 것입니다!

나는 그것을 인정할 수있다!

확장 메서드를 사용하는 순환 연결 목록

이제 이들을 결합하고 확장 메서드 코드를 사용하여 다음과 같이 읽습니다.

myNode.NextOrFirst().DisplayInMyWay();

보다는

DisplayInMyWay(NextOrFirst(myNode)).

확장 방법 사용 더 깔끔하고 읽기 쉽고 객체 지향적입니다. 또한 매우 가깝습니다 :

myNode.Next.DoSomething()

동료에게 보여주세요! :)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.