C#拡張メソッドでクラスを拡張するにはどうすればよいですか?


98

クラスに拡張メソッドを適用できますか?

たとえば、DateTimeを拡張して、次のように呼び出すことができるTomorrow()メソッドを含めます。

DateTime.Tomorrow();

私は使用できることを知っています

static DateTime Tomorrow(this Datetime value) { //... }

または

public static MyClass {
  public static Tomorrow() { //... }
}

同様の結果が得られますが、DateTime.Tomorrowを呼び出せるようにDateTimeを拡張するにはどうすればよいですか?

回答:


70

既存のタイプが部分的としてマークされていない限り、既存のタイプにメソッドを追加することはできません。拡張メソッドを通じて、既存のタイプのメンバーであるように見えるメソッドのみを追加できます。拡張メソッドはその型のインスタンスを使用するため、これは静的メソッドを型自体に追加できないためです。

次のような独自の静的ヘルパーメソッドの作成を妨げるものは何もありません。

static class DateTimeHelper
{
    public static DateTime Tomorrow
    {
        get { return DateTime.Now.AddDays(1); }
    }
}

あなたはこのように使います:

DateTime tomorrow = DateTimeHelper.Tomorrow;

6
えっ?これから 6か月以内に実装されていない限り、Kumuの答えはすぐに完成しません。
cregox

4
@Cawasこれは不完全ではありません。Andrewは、拡張メソッドではなく静的ヘルパーを使用してこれを行う方法を示しています(インスタンスがないため)。
Nick N. 14

1
あなたは正しい、ニック。私は拡張メソッドが好きです!;)
cregox 2014

2
extensionmethod.net/csharp/datetime私見、学習曲線を最小限に抑えるためのより良いサンプルは、完全なソースコードと優れたパターンを備えた実際のアプリケーションです
Kiquenet

3
このコードの問題は、DateTime.Nowでのみ機能し、DateTimeオブジェクトでは機能しないことです。ユーティリティとして、前(または未来)の翌日の決定に使用することができます。言うまでもなく、DateTime.Nowは呼び出すたびに決定されます...
MintGrowth

181

拡張メソッドを使用します。

例:

namespace ExtensionMethods
{
    public static class MyExtensionMethods
    {
        public static DateTime Tomorrow(this DateTime date)
        {
            return date.AddDays(1);
        }    
    }
}

使用法:

DateTime.Now.Tomorrow();

または

AnyObjectOfTypeDateTime.Tomorrow();

2
Shuggyの回答も、これを解決するための同様の方法にいくつかの光を投げかけました
cregox

8
「Using ExtensionMethods;」を忘れないでください。これについては、ドキュメントの上部にあります。
ルークアルダートン2013

なぜDateTime.Tomorrow()を実行できないのですか?
lawphotog 2014

こんにちはlawphotog、この拡張機能にはオブジェクトが必要です。ここで、DateTimeは構造体であり、オブジェクトではありません。
Kumu 14

4
以前のコメントで述べたように(明らかに私には十分に明確ではありませんでした)、DateTime.Tomorrow()拡張メソッドはクラスのインスタンスとクラス構造体でのみ機能するため、使用することはできません。クラス構造体の静的メソッドを「拡張」するには、Andrewの回答またはShuggyの回答に従ってください
アレックス

18

拡張メソッドは、最初のパラメーターがT型のインスタンスである静的メソッドを、Tのインスタンスメソッドのように見せるための構文糖です。

そのため、「静的拡張メソッド」を作成すると、拡張メソッドよりもコードの読者を混乱させるので、メリットはほとんど失われます(完全修飾されているように見えますが、実際にはそのクラスで定義されていないため)。構文上の利点はありません(たとえば、Linq内で流暢なスタイルで呼び出しをチェーンできるため)。

とにかく使用して拡張機能をスコープに組み込む必要があるので、作成する方が簡単で安全であると私は主張します。

public static class DateTimeUtils
{
    public static DateTime Tomorrow { get { ... } }
}

そして、あなたのコードでこれを使ってください:

WriteLine("{0}", DateTimeUtils.Tomorrow)

11

答えに最も近いのは、System.Typeオブジェクトに拡張メソッドを追加することです。きれいではありませんが、それでも面白いです。

public static class Foo
{
    public static void Bar()
    {
        var now = DateTime.Now;
        var tomorrow = typeof(DateTime).Tomorrow();
    }

    public static DateTime Tomorrow(this System.Type type)
    {
        if (type == typeof(DateTime)) {
            return DateTime.Now.AddDays(1);
        } else {
            throw new InvalidOperationException();
        }
    }
}

それ以外の場合は、IMO AndrewとShuggyCoUkの方が実装が優れています。


このアプローチには問題があります。「typeof(...)」と入力する必要はありません。インテリセンスを使用すると、すべての型の拡張機能が表示されます。それでも、これは私が考えていなかった興味深いアプローチです、+ 1。
メタナイト

@ Meta-Knight True、それが個人的に私が相手の答えを好む理由です。私の答えはOPの質問に最も近い構文になりますが、この問題を解決する最良の方法ではありません。
エイドリアン・ゴドン

Type必要な他のタイプと置き換えることができます。私はそれを使ってFrom、それは完全に機能します。この答えは一般的ですが正しいと思います
Katia

3

クムと同じです

namespace ExtensionMethods
{
    public static class MyExtensionMethods
    {
        public static DateTime Tomorrow(this DateTime date)
        {
           return date.AddDays(1);
        }    
    }
}

しかし、この新しいDateTime()。Tomorrow();のように呼び出します。

DateTime.Now.Tomorrow();よりも多く見られるようになると思います。


1
そして、あなたはクムの答えへのコメントとしてそれを書く機会を逃しました!:P
cregox

3

これらは、型に変更を加えることなく新しいメソッドを追加することにより、既存の型を拡張する機能を提供します。インスタンスメソッド構文を使用してアプリケーション内の拡張型のオブジェクトからメソッドを呼び出すことは、「拡張」メソッドと呼ばれます。拡張メソッドは、型のインスタンスメンバーではありません。覚えておくべき重要な点は、静的メソッドとして定義されている拡張メソッドは、usingディレクティブを介して名前空間がアプリケーションのソースコードに明示的にインポートされた場合にのみスコープ内にあるということです。拡張メソッドは静的メソッドとして定義されていますが、インスタンス構文を使用して呼び出されます。

完全な例をここで確認して くださいhttp://www.dotnetreaders.com/articles/Extension_methods_in_C-sharp.net,Methods_in_C_-sharp/201

例:

class Extension
    {
        static void Main(string[] args)
        {
            string s = "sudhakar";
            Console.WriteLine(s.GetWordCount());
            Console.ReadLine();
        }

    }
    public static class MyMathExtension
    {

        public static int GetWordCount(this System.String mystring)
        {
            return mystring.Length;
        }
    }

3

私は似たようなものを探していました-拡張メソッドを提供するクラスの制約のリスト。簡潔なリストを見つけるのは難しいので、ここに行きます:

  1. フィールドやメソッドなど、プライベートなものや保護されたものを持つことはできません。

  2. のように、静的クラスである必要がありますpublic static class...

  3. クラスに入れることができるのはメソッドのみであり、それらはすべてpublic staticでなければなりません。

  4. 従来の静的メソッドを持つことはできません-this引数を含まないメソッドは許可されません。

  5. すべてのメソッドを開始する必要があります:

    public static ReturnType MethodName(this ClassName _this、...)

したがって、最初の引数は常にthis参照です。

これにより暗黙の問題が発生します。何らかのロックを必要とするメソッドを追加した場合、実際にはクラスレベルでそれを提供することはできません。通常、プライベートインスタンスレベルのロックを提供しますが、プライベートフィールドを追加することはできないため、外部クラスでパブリックスタティックとして提供するなど、非常に厄介なオプションが残ります。C#言語のサインは、これらのデザインにちょっと悪い方向を向いていました

回避策は、Extension Methodクラスを通常のクラスのFacadeとして使用することです。Extensionクラスのすべての静的メソッドは、おそらくシングルトンを使用し、実際のクラスを呼び出すだけです。


2

残念ながらそれはできません。しかし、それは有用だと思います。入力する方が自然です:

DateTime.Tomorrow

より:

DateTimeUtil.Tomorrow

Utilクラスでは、静的メソッドが1つではなく2つの異なるクラスに存在するかどうかを確認する必要があります。


1

詳しい説明で回答を改善しました。拡張方法がわかりやすくなりました。

拡張メソッド:これは、サブクラス化を使用したり、元のクラスまたは構造体を変更または再コンパイルすることなく、既存のクラスの動作を拡張できるメカニズムです。

カスタムクラス、.netフレームワーククラスなどを拡張できます。

拡張メソッドは、実際には静的クラスで定義されている特殊な静的メソッドです。

DateTimeクラス既に上記取得され、したがって、私たちは説明のために、このクラスを取っていません。

以下は例です

//これはメソッドが1つしかない既存のCalculatorクラスです(追加)

public class Calculator 
{
    public double Add(double num1, double num2)
    {
        return num1 + num2;
    }

}

// Below is the extension class which have one extension method.  
public static class Extension
{
    // It is extension method and it's first parameter is a calculator class.It's behavior is going to extend. 
    public static double Division(this Calculator cal, double num1,double num2){
       return num1 / num2;
    }   
}

// We have tested the extension method below.        
class Program
{
    static void Main(string[] args)
    {
        Calculator cal = new Calculator();
        double add=cal.Add(10, 10);
        // It is a extension method in Calculator class.
        double add=cal.Division(100, 10)

    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.