3

Pythonでは、C#selfの場合と同様に、インスタンスメソッドはクラスインスタンスを指します。thisPythonでは、クラスメソッドはクラスをself指します。C#に相当するものはありますか?

これは便利です。例:

Pythonの例:

class A:
  values = [1,2]

  @classmethod
  def Foo(self):
    print "Foo called in class: ", self, self.values

  @staticmethod
  def Bar():
    print "Same for all classes - there is no self"

class B(A):
  # other code specific to class B
  values = [1,2,3]
  pass

class C(A):
  # other code specific to class C
  values = [1,2,3,4,5]
  pass

A.Foo()
A.Bar()
B.Foo()
B.Bar()
C.Foo()
C.Bar()

結果:

Foo called in class:  __main__.A [1, 2]
Same for all classes - there is no self
Foo called in class:  __main__.B [1, 2, 3]
Same for all classes - there is no self
Foo called in class:  __main__.C [1, 2, 3, 4, 5]
Same for all classes - there is no self

これは、クラスコンテキスト(インスタンスなし)の一般的なコードが(サブクラスのインスタンスを必要とせずに)サブクラスによって定義されるカスタマイズされた動作を提供できるようにするための優れたツールになります。

C#静的メソッドは、メソッドを呼び出すために実際に使用されたクラスへのアクセスがないという点で、pythons静的メソッドとまったく同じように見えます。

しかし、C#でクラスメソッドを実行する方法はありますか?または、少なくとも、どのクラスがメソッドを呼び出したかを判別します。次に例を示します。

public class A
{
  public static List<int> values;

  public static Foo()
  {
    Console.WriteLine("How can I figure out which class called this method?");
  }
}

public class B : A
{
}

public class C : A
{
}

public class Program
{
  public static void Main()
  {
    A.Foo();
    B.Foo();
    C.Foo();
  }
}
4

4 に答える 4

4

通常の静的メソッドを使用してこれを行う方法はありません。可能な代替案は次のとおりです。

1)仮想のオーバーライドされたインスタンスメソッド:

public class A
{
    public virtual void Foo()
    {
        Console.WriteLine("Called from A");
    }
}

public class B : A
{
    public override void Foo()
    {
        Console.WriteLine("Called from B");
    }
}

2)拡張方法:

public class A
{
}

public class B : A
{
}

public static class Extensions
{
    /// Allows you to do:
    /// var whoop = new B();
    /// whoop.Foo();
    public static void Foo<T>(this T thing) where T : A
    {
        Console.WriteLine("Called from " + thing.GetType().Name);
    }
}

3)AとBにデフォルトのコンストラクターがあると仮定します。

public static class Cached<T> where T : class, new()
{
    private static T _cachedInstance;

    public static T Instance
    {
        get { return _cachedInstance ?? (_cachedInstance = new T()); }
    }
}

public static class Extensions
{
    public static void Example()
    {
        Cached<B>.Instance.Foo();
    }

    public static void Foo<T>(this T thing) where T : A, new()
    {
        Console.WriteLine("Called from " + typeof(T).Name);
    }
}
于 2011-08-19T00:35:21.263 に答える
1

そうではありません。各呼び出しメソッドは、それ自体とthis変数を静的に利用可能なスタックまたはディクショナリにプッシュする必要があります。

CallContextを使用して、呼び出しスタックを格納することを検討できます。私はかつて、このようなメカニズムを使用して、スタックベースの情報を関数呼び出しチェーンに格納していました。

PostsharpのようなAOPフレームワークを使用して処理することができますCallContext。それが私がしたことです。私はまさにこの目的のためにそれを使用しました。私は自分のアプリにIronPythonを埋め込んでいて、IronPythonの呼び出しを開始したC#オブジェクトとメソッドを識別する方法が必要でした。それはかなりうまくいきました。残念ながら、私はもうそのコードを持っていません。

于 2011-08-19T00:25:15.503 に答える
0

C#の対応するコードは次のとおりです。

public class A {

  protected int[] values;

  public A () {
    values = new int[] { 1, 2 };
  }

  public void Foo() {
    Console.WriteLine("Foo called in class: {0}, values = {1}", this.GetType().Name, String.Join(",", values));
  }

  public static void Bar() {
    Console.WriteLine("Same for all classes.");
  }

}

public class B : A {

  public B () {
    values = new int[] { 1, 2, 3 };
  }

}

public class C : A {

  public C () {
    values = new int[] { 1, 2, 3, 4, 5 };
  }

}

インスタンスメソッドを呼び出すには、クラスのインスタンスを作成する必要があります。

new A().Foo();
A.Bar();
new B().Foo();
B.Bar();
new C().Foo();
C.Bar();

出力:

Foo called in class: A, values = 1,2
Same for all classes.
Foo called in class: B, values = 1,2,3
Same for all classes.
Foo called in class: C, values = 1,2,3,4,5
Same for all classes.

呼び出すC.Bar()ことは呼び出すことと同じA.Bar()であり、メソッドは違いを認識しません。メソッドはAクラス内にありますが、コンパイラーでは、派生クラスを使用してメソッドを呼び出すこともできます。

于 2011-08-19T00:40:11.257 に答える
0

ジェネリックを使用してこれを行うことができます

public class _A<T> where T : _A<T> {

  public static int[] Values=new int[] {1,2};

  public static void Foo() {
    Console.WriteLine(String.Format("Foo called in class: {0} {1}",typeof(T).Name, String.Join(",",T.Values)));
  }
}

public class A : _A<A> {
}

public class B : _A<B> {
  public static new int[] Values=new int[] {1,2,3};
}

public class C : _A<C> {
  public static new int[] Values=new int[] {1,2,3,4,5};
}

難しいのは、Aを使用するには型変数を知っている必要があるため、A.Foo()は実行できませんが、B.Foo()とC.Foo()は実行できます。ただし、A.Foo()を使用して取得することはできます

于 2011-08-19T01:10:17.997 に答える