3

在 python 中,实例方法self指向类实例,就像this在 C# 中一样。在python中,类方法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# 静态方法与 python 的静态方法完全一样,因为无法访问实际使用哪个类来调用该方法。

但是有没有办法在 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};
}

困难在于您需要知道 Type 变量才能使用 A,因此您不能使用 A.Foo(),但可以使用 B.Foo() 和 C.Foo()。但是你可以 A.Foo() 并得到

于 2011-08-19T01:10:17.997 回答