有没有一种方法可以在c#中像python一样创建类方法?
本文关键字:python 一样 类方法 中像 创建 一种 方法 有没有 | 更新日期: 2023-09-27 18:06:17
在python中,实例方法self
指向类实例,就像c#中的this
一样。在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();
}
}
使用常规静态方法是无法做到这一点的。可能的替代方案包括:
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);
}
}
并非如此。每个调用方法都必须将自己和this
变量推到某个静态可用的堆栈或字典中。
您可以探索使用CallContext
来存储调用堆栈。我曾经使用这种机制在函数调用链上存储基于堆栈的信息。
你可以使用像Postsharp这样的AOP框架来处理CallContext
的东西。我就是这么做的。我用它就是为了这个目的。我正在将IronPython嵌入到我的应用程序中,并且想要一种方法来识别启动对IronPython调用的c#对象和方法。它运行得很好。不幸的是,我没有那个代码了。
下面是相应的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
类中,但编译器也允许您使用派生类调用它。
您可以使用泛型来完成此操作
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.f foo()并获得