함수 매개 변수의 "this"


88

HtmlHelpers에 대한 몇 가지 코드 예제를 살펴보면 다음과 같은 선언이 표시됩니다.

public static string HelperName(this HtmlHelper htmlHelper, ...more regular params )

다른 곳에서는 이런 유형의 구조를 본 기억이 없습니다. 누군가 "this"의 목적을 설명 할 수 있습니까? 나는 무언가를 public static으로 선언함으로써 클래스가 인스턴스화 될 필요가 없다는 것을 의미한다고 생각했습니다. 그래서이 경우 "this"는 무엇입니까?

답변:


212

C # 3.0의 새로운 기능인 확장 메서드를 선언하는 구문입니다.

확장 메서드는 부분 코드, 부분 컴파일러 "마법"으로, Visual Studio의 인텔리 젠스를 사용하여 컴파일러가 실제로 해당 개체의 인스턴스 메서드로 확장 메서드를 사용할 수 있음을 나타냅니다.

예를 들어 보겠습니다.

GobbleGobble이라는 String 클래스에는 메서드가 없으므로 확장 메서드를 만들어 보겠습니다.

public static class StringExtensions
{
    public static void GobbleGobble(this string s)
    {
        Console.Out.WriteLine("Gobble Gobble, " + s);
    }
}

클래스 이름은 내 명명 규칙 일뿐입니다. 그렇게 이름을 지정할 필요는 없지만 메서드와 마찬가지로 정적이어야합니다.

위의 메서드를 선언 한 후 Visual Studio에서 다음을 입력 할 수 있습니다.

String s = "Turkey Baster!";
s.

점 다음에 intellisense를 기다렸다가 GobbleGobble 메소드가 있는지 확인하고 다음과 같이 코드를 완성합니다.

String s = "Turkey Baster!";
s.GobbleGobble();

중요 : intellisense가 메서드를 표시하려면 확장 메서드가 선언 된 클래스가 컴파일러 및 intellisense 프로세서에서 사용 가능해야합니다. GobbleGobble을 수동으로 입력하고 Ctrl+ .단축키를 사용하면 올바른 using 지시문을 파일로 가져 오는 데 도움이되지 않습니다.

메소드에 대한 매개 변수가 사라졌습니다. 컴파일러는 다음과 같은 중요한 부분을 조용히 이동합니다.

String s = "Turkey Baster!";
s.GobbleGobble();
^     ^
|     +-- the compiler will find this in the StringExtensions class
|
+-- will be used as the first parameter to the method

따라서 위의 코드는 컴파일러에 의해 다음과 같이 변환됩니다.

String s = "Turkey Baster!";
StringExtensions.GobbleGobble(s);

따라서 호출 시간에는 마법 같은 것이 없으며 정적 메서드에 대한 호출 일뿐입니다.

확장 메소드가 둘 이상의 매개 변수를 선언하는 경우 첫 번째 매개 변수 만 this수정자를 지원 하고 나머지는 정상적으로 메소드 호출의 일부로 지정되어야합니다.

public static void GobbleGobble(this string value, string extra)
{                                            |              |
    ...                                      |              |
}                                            |              |
                                             |              |
+--------------------------------------------+              |
|                                                           |
v                                                           |
s.GobbleGobble("extra goes here");                          |
                        ^                                   |
                        |                                   |
                        +-----------------------------------+

확장 메서드는 Linq로 인해 부분적으로 추가되었습니다. 여기서 C #의 Linq 구문은 실행중인 개체에 대해 적절하게 명명 된 확장 메서드를 찾습니다. 즉, 올바른 확장을 선언하여 모든 유형의 클래스에 Linq 지원을 "소개"할 수 있습니다. 행동 양식. 물론 전체 Linq 지원은 많은 작업이지만 가능합니다.

또한 확장 방법 자체가 정말 유용하므로 읽어보십시오.

다음은 몇 가지 링크입니다.


6
나는 확실히 "Gobble Gobble Magic"이라는 용어를 사용하기 시작할 것입니다.
chris

Youtube는 링크를 다시 끊었습니다. youtube.com/watch?v=Bz_heb9Rz2g , 여전히 @ 1 : 00 이상입니다.
Lasse V. Karlsen 2013 년

이러한 종류의 컴파일러 마법은 언어를 배우는 것을 어렵게 만듭니다.
Don Dilanga

8

확장 방법 이후 미친 듯이 사용해 왔는데 .. 계속해서 사용하는 몇 가지 방법이 있습니다.

public static T ChangeType<T>(this object obj)
{
  return (T)Convert.ChangeType(obj, typeof(T));
}

이렇게 작동합니다 ..

int i = "123".ChangeType<int>();
bool valid = "bool".ChangeType<bool>();
int id = dataSet.Tables[0].Rows[0]["Id"].ChangeType<int>();

예, 그것은 모든 단일 객체에 나타나고 성 가실 수 있지만 거의 모든 데이터 유형에 이것을 사용하기 때문에 가능한 모든 데이터 유형에 대해 복제하는 대신 객체에 첨부하는 것이 좋습니다.

public static string ToXml(this object serializableObject)
{
    var aMemStr = new MemoryStream();
    try
    {
        var serializer = new XmlSerializer(serializableObject.GetType());
        serializer.Serialize(new XmlTextWriter(aMemStr, null), serializableObject);
        return Encoding.UTF8.GetString(aMemStr.ToArray());
    }
    finally { if (aMemStr != null) { aMemStr.Dispose(); } }
}

string xml = dataSet.ToXml();

public static T ToObject<T>(this string xmlString)
{
    var aStream = new MemoryStream(Encoding.UTF8.GetBytes(xmlString));
    try { return (T)new XmlSerializer(typeof(T)).Deserialize(aStream); }
    finally { if (aStream != null) { aStream.Dispose(); aStream = null; } }
}

DataSet dataSet = xml.ToObject<DataSet>();

6

확장 방법에 사용됩니다. 기본적으로 Helpername을 htmlHelper 개체에 '접착'하면 다음과 같이 말할 수 있습니다.

new HtmlHelper().HelperName(...more regular params);

4

그것은 확장 방법입니다. 원본 클래스 외부에있는 정적 메서드를 통해 클래스를 "확장"할 수 있습니다.

예를 들어, 항상 사용하는 유용한 문자열 방법이 있다고 가정합니다.

public int CountAllAs(string orig)
{
    return orig.ToLowerInvariant().ToArray().Count(c => c == 'a');
}

그리고 당신은 그것을 ...

string allAs = "aaaA";
int count = CountAllAs(allAs);

그렇게 나쁘지 않습니다. 그러나 약간만 변경하면 Extension 메서드로 만들 수 있으며 호출이 좀 더 예쁘게됩니다.

public static int CountAllAs(this string orig)
{
    return orig.ToLowerInvariant().ToArray().Count(c => c == 'a');
}

그리고 그것을 ...

string allAs = "aaaA";
int count = allAs.CountAllAs();

3

확장 방법 ...

... 데코레이터 패턴을 사용하는 경우와 같은 기능을 포함하는 환상적인 방법 이지만 모든 코드를 리팩토링하거나 공통 유형의 다른 이름을 사용하는 불편 함이 없습니다.

public static class Extensions
{
     public static string RemoveComma(this string value)
     {
         if (value == null) throw new ArgumentNullException("value");
        return value.Replace(",", "");
    }
}  

따라서 앱 어디에서나이 코드를 사용할 수 있습니다.

Console.WriteLine(“Hello, My, Friend”.RemoveComma())

>> Hello My Friend

그렇게 명령 속성 확장은 "추가"됩니다 유형을 의미, 그리고 그것을 매개 변수로 전달 된 것처럼 당신이 값으로 작업 할 수 있습니다.

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