Is there a way to make classmethods in C# like python?
In python, an instance method self
points to the class instance, just like this
in C#.
In python, a class method self
points to the class. Is there a C# equivalent?
This can be useful, example:
Python example:
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()
Results in:
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
This can be a great tool so that common code in a class context (without an instance) can provide customised behaviour that is defined by the subclass (without requiring an instance of the subclass).
It seems to me that C# static methods are exactly like pythons static methods, in that there is no access to which class was actually used to invoke the method.
But is there a way to do class methods in C#?? Or at least determine which class invoked a method, for example:
public class A
{
public static List<int> values;
public static Foo()
{
Console.WriteLine("How can I figure out which class called this me开发者_运维问答thod?");
}
}
public class B : A
{
}
public class C : A
{
}
public class Program
{
public static void Main()
{
A.Foo();
B.Foo();
C.Foo();
}
}
There is no way to do this using regular static methods. Possible alternatives include:
1) Virtual, overridden instance methods:
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) Extension methods:
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) Assuming A and B have a default constructor:
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);
}
}
Not as such. Each calling method would have to push itself and the this
variable onto some staticly-available stack or dictionary.
You could explore using CallContext
to store the calling stack. I once used such a mechanism to store stack-based information on a function call chain.
You could use an AOP framework like Postsharp to handle the CallContext
stuff. That's what I did. I used it for this exact purpose. I was embedding IronPython into my app, and wanted a way to identify the C# object and method that initiated a call into IronPython. It worked pretty well. Unfortunately, I do not have that code anymore.
Here is the corresponding code in 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 };
}
}
To call the instance methods you need to create instances of the classes:
new A().Foo();
A.Bar();
new B().Foo();
B.Bar();
new C().Foo();
C.Bar();
Output:
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.
Calling C.Bar()
is equivalent to calling A.Bar()
, the method will not be aware of the difference. The method is in the A
class, but the compiler lets you call it using the derived classes also.
You could use generics to do this
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};
}
The difficulty is that you would need to know the Type variable to use A so you couldn't do A.Foo() but you could do B.Foo() and C.Foo(). You could however to A.Foo() and get
精彩评论