web-dev-qa-db-ja.com

C#:派生クラスの静的メソッドから基本クラスの静的メソッドを呼び出すにはどうすればよいですか?

C#には、基本クラスのProductと派生クラスのWidgetがあります。

製品には静的メソッドMyMethod()が含まれています。

静的メソッドWidget.MyMethod()から静的メソッドProduct.MyMethod()を呼び出したい。

Baseキーワードはインスタンスメソッドでのみ機能するため、使用できません。

Product.MyMethod()を明示的に呼び出すことはできますが、後でWidgetを変更して別のクラスから派生させる場合は、メソッドを修正する必要があります。

派生クラスの静的メソッドから基本クラスから静的メソッドを呼び出すことができるbaseに似たC#の構文はありますか?

17
MindModel

staticメソッドは基本的に、オブジェクト指向の概念からフォールバックするためのメソッドです。結果として、それらは継承階層であまり柔軟ではなく、そのようなことを直接行うことはできません。

私が考えることができる最も近いものは、usingディレクティブです。

using mybaseclass = Namespace.BaseClass;

class MyClass : mybaseclass {

  static void MyMethod() {  mybaseclass.BaseStaticMethod();  }

}
18
Mehrdad Afshari

それは可能ですが、私はお勧めしません。

public class Parent1
{
    public static void Foo()
    {
        Console.WriteLine("Parent1");
    }
}

public class Child : Parent1
{
    public new static void Foo()
    {
        Type parent = typeof(Child).BaseType;
        MethodInfo[] methods = parent.GetMethods();
        MethodInfo foo = methods.First(m => m.Name == "Foo");
        foo.Invoke(null, null);
    }
}
4
marcumka

リフレクションを使用して静的メソッドを呼び出すことは、インスタンスにnullを渡すことを除いて、インスタンスメソッドを呼び出すこととまったく同じです。 FlattenHierarchyは祖先で定義されているため、必要です。

var type = assy.GetType("MyNamespace.MyType");
MethodInfo mi = type.GetMethod("MyStaticMethod", 
  BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy);
mi.Invoke(null, null);

さらに読んで考えると、回答した他の人と同じ質問をすることになります。なぜこのような静的メソッドを使用するのですか?関数型プログラミングをしようとしていますか?もしそうなら、代わりにラムダ式を使用しませんか?共有状態のポリモフィックな動作が必要な場合は、インスタンスメソッドの方が適しています。

4
Peter Wone

それを行うことができます:

public class Parent1
{
    protected static void Foo()
    {
        Console.WriteLine("Parent1");
    }
}

public class Child : Parent1
{
    public static void Foo()
    {
        return Parent1.Foo();
    }
}

保護された静的メソッドの単体テストに役立ちます(たとえば)。

3
mlipman

何よりもまず、クラスの子育てを心配している場合は、継承が間違っている可能性があります。継承は、単にコードの再利用を促進するのではなく、「is-a」関係を確立するために使用する必要があります。コードを単独で再利用する必要がある場合は、継承ではなく委任の使用を検討してください。サブタイプとその親の間に中間タイプを導入できると思いますが、その可能性が私の設計を推進させます。

次に、基本クラスの機能を使用する必要があるが、それを拡張し、ユースケースが静的メソッドを呼び出す場合は、機能を保持するために外部クラスの使用を検討することをお勧めします。私の頭の中でこれの典型的なケースはファクトリーパターンです。ファクトリパターンを実装する1つの方法は、そのクラスのインスタンスを構築するクラスの静的メソッドであるファクトリメソッドを使用することです。通常、コンストラクターは保護されているため、ファクトリメソッドが外部からクラスをビルドする唯一の方法です。

継承階層のファクトリメソッドで再利用する方法の1つは、共通コードを保護されたメソッドに配置し、サブタイプのファクトリメソッドから基本クラスのファクトリメソッドを直接呼び出すのではなく、ファクトリメソッドからそのメソッドを呼び出すことです。より良い実装では、同じ手法を使用しますが、ファクトリメソッドをファクトリクラスに移動し、コンストラクタロジック(プライベートではなく内部)を使用して、おそらく初期化メソッドと組み合わせてオブジェクトを作成します。継承する動作がクラスの外部(復号化/検証など)である場合は、ファクトリ内で共有メソッド(または構成)を使用して、ファクトリメソッド間で再利用できます。

静的メソッドの使用の目的を知らなければ、正確な方向性を示すことは困難ですが、これが役立つことを願っています。

2
tvanfosson

静的メソッドはポリモーフィックではないため、やりたいことは不可能です。

静的メソッドを多形として扱う方法を見つけようとすることは可能ですが、言語自体がそれをサポートしていないため危険です。

いくつかの提案:

  • 反射
  • 基本クラスのエイリアシング( Mehrdadの例 など)
1
Michael Meadows

静的メソッドは「クラスレベル」のメソッドです。これらは、特定のクラスのすべてのインスタンスに適用されるメソッドであることが意図されています。したがって、このメソッドの継承は、クラスのインスタンスに適用する意味を変更するため、意味がありません。たとえば、Productsのコレクション(ウィジェットの一部とそうでないもの)をループし、各ProductでMyMethodを呼び出した場合、呼び出されたメソッドはクラスのインスタンスによって決定されます。これは静的メソッドの目的に違反します。

あなたの例ではMyMethodがProductのすべてのインスタンスに適用されるようには見えないので、静的メソッドをまったく使用しないことで、おそらくもっときれいにしたいことをすることができます。ただし、「IMyMethod」などのインターフェイスクラスを使用すると、説明しているのと同じ効果を得ることができます。このアプローチはまだ静的メソッドを使用していません。静的メソッドの必要性は見られないと思います。そもそもなぜ静的メソッドを使いたいのですか?

0
Dunk

静的メソッドはインスタンスデータを中継してはならないことを考慮に入れて...パラメータなどに基づいて異なる動作をする静的な「MyMethod」が必要です。

1つのクラスで定義された静的メソッドは、コードを順序付ける方法にすぎないことを忘れないでください...ただし、そのメソッドが他の場所に配置されている場合も同じです...配置されているオブジェクトを中継しないためです。

編集:最善の選択はProduct.MyMethodを明示的に使用することだと思います...あなたがそれを考えるなら...あなたのウィジェットがそのベースクラスを変更する可能性はないはずです...そしてまたその場合、それはコードのマイナーな変更です。

0
Romias

とても簡単です。エイリアシング、リフレクションなどを使用するよりもはるかに簡単です。NET、IDKの新しい追加で簡単になったかもしれませんが、これは完全に正常に機能します。インスタンスメソッドの場合と同様に、基本メソッドにアクセスするためにbaseを使用する必要はありません。これはオプションであり、通常、継承クラスと基本クラスに同じ名前のメソッドがある場合に必要です。 baseキーワードがなくても、呼び出し元のクラスにあるかのように、基本クラスの静的メソッドにアクセスできます。これは、派生クラスのstaticメソッドからベースstaticメソッドを呼び出すときにのみテストしました。 instanceメソッドから静的メソッドを呼び出す場合は機能しない可能性があります。

public class BaseThings
{
    protected static void AssertPermissions()
    {
        //something
    }
}

public class Person:BaseThings
{
    public static void ValidatePerson(Person person)
    {
        //just call the base static method as if it were in this class.
        AssertPermissions();            
    }
}
0
AaronLS