関数パラメータの「this」


88

HtmlHelpersのいくつかのコード例を見ると、次のような宣言があります。

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

このタイプのコンストラクトを他の場所で見たのを覚えていません-誰かが「これ」の目的を説明できますか?public staticを宣言することは、クラスをインスタンス化する必要がないことを意味すると思いました。この場合の「これ」とは何でしょうか。

回答:


212

これは、C#3.0の新機能である拡張メソッドを宣言するための構文です。

拡張メソッドは、パーツコード、パーツコンパイラの「魔法」であり、Visual Studioのインテリセンスを利用したコンパイラにより、拡張メソッドが問題のオブジェクトのインスタンスメソッドとして実際に使用可能であるように見えます。

例を挙げましょう。

StringクラスにはGobbleGobbleという名前のメソッドがないので、拡張メソッドを作成しましょう。

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

クラス名は私の命名規則にすぎません。そのように名前を付ける必要はありませんが、メソッドと同様に静的である必要があります。

上記のメソッドを宣言した後、VisualStudioで次のように入力できます。

String s = "Turkey Baster!";
s.

ドットの後、インテリセンスを待ち、そこにGobbleGobbleメソッドがあることに気づき、次のようなコードを完成させます。

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

重要:拡張メソッドが宣言されているクラスは、インテリセンスがメソッドを表示するために、コンパイラーとインテリセンスプロセッサーが使用できる必要があります。GobbleGobbleを手動で入力し、Ctrl+.ショートカットを使用する場合、ファイルへのディレクティブを正しく使用するのに役立ちません。

メソッドのパラメーターが消えていることに注意してください。コンパイラは、次の重要なビットをサイレントに移動します。

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");                          |
                        ^                                   |
                        |                                   |
                        +-----------------------------------+

拡張メソッドが追加された理由の1つは、C#のLinq構文が、再生中のオブジェクトに対して適切な名前の拡張メソッドを検索することです。つまり、適切な拡張を宣言するだけで、Linqサポートを任意のタイプのクラスに「導入」できます。メソッド。もちろん、Linqの完全サポートは大変な作業ですが、それは可能です。

また、拡張メソッド自体は非常に便利なので、よく読んでください。

ここにいくつかのリンクがあります:


6
私は間違いなく「GobbleGobbleMagic」という用語を使い始めるつもりです。
クリス2010年

Youtubeは、youtube.com / watch?v = Bz_heb9Rz2gで、まだ@ 1:00以降にリンクを解除しました。
Lasse V. Karlsen 2013年

この種のコンパイラの魔法は、言語を学ぶことを困難にします。
ドンディランガ

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

これはextensionmethodsに使用されます。基本的に、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.