2010-01-13 106 views
6

有沒有辦法做什麼classmethod在Python在Python中做的?C#的Python風格的classmethod?

也就是說,一個靜態函數將根據使用的任何子類將Type對象作爲(隱式)參數。

的我想要的一個例子,大約是

class Base: 
    @classmethod 
    def get(cls, id): 
     print "Would instantiate a new %r with ID %d."%(cls, id) 

class Puppy(Base): 
    pass 

class Kitten(Base): 
    pass 

p = Puppy.get(1) 
k = Kitten.get(1) 

預期的輸出是

Would instantiate a new <class __main__.Puppy at 0x403533ec> with ID 1. 
Would instantiate a new <class __main__.Kitten at 0x4035341c> with ID 1. 

(same code on codepad here.)

回答

1

原則上,你可以是這樣的:

class Base 
{ 
    public static T Get<T>(int id) 
     where T : Base, new() 
    { 
     return new T() { ID = id }; 
    } 

    public int ID { get; set; } 
} 

然後,你可以寫var p = Base.Get<Puppy>(10)。或者,如果你感到受虐狂,你可以寫Puppy.Get<Puppy>(10),甚至Kitty.Get<Puppy>;)在所有情況下,你必須明確地傳遞類型,而不是隱含的。

或者,這也工作:

class Base<T> where T : Base<T>, new() 
{ 
    public static T Get(int id) 
    { 
     return new T() { ID = id }; 
    } 

    public int ID { get; set; } 
} 

class Puppy : Base<Puppy> 
{ 
} 

class Kitten : Base<Kitten> 
{ 
} 

您仍然需要通過類型備份到基類,它允許你寫Puppy.Get(10)預期。

但是,仍然有這樣寫的原因,當var p = new Puppy(10)是一樣簡潔和更習慣?可能不會。

2

根據上下文,你要麼需要仿製藥或虛擬方法。

0

這相當於Object Pascal中的類方法。 (.Net實現將是RemObject的oxygene)。

但是,雖然在原始平臺上有類引用,因此虛擬類方法或看似靜態方法可以訪問某些類級別的狀態,但我認爲它們對於.Net或C#沒有多大意義。

我以前也在Oxygene中編程了好幾年,而且我從不需要類的引用。

不是因爲我不知道如何使用它們。在「原始」ObjectPascal平臺上,原生Delphi,我用它們全部爲的時候。但是因爲.Net和BCL沒有真正的支持它們,所以使用它們沒有任何優勢。而像Python或原生Delphi這樣的平臺確實在他們的庫中支持它們。

你顯然不想要一個靜態方法,你想要的是可以有狀態和/或支持繼承的東西。所以無論是工廠,還是你的構造函數都可能會很好。

0

因爲C#是靜態編譯的,所以在編譯時調用Puppy.get(),例如。已知指向Base.get(),這意味着生成的CIL(公共中間語言)將有一個呼叫指令到Base.get()

.method private hidebysig static void Main() cil managed 
{ 
    .entrypoint 
    // Code size  9 (0x9) 
    .maxstack 8 
    IL_0000: nop 
    IL_0001: ldc.i4.1 
    IL_0002: call  void Base::get(int32) 
    IL_0007: nop 
    IL_0008: ret 
}