2010-01-13 11 views
6

C'è un modo per fare ciò che fa classmethod in Python in C#?classmethod in stile Python per C#?

Cioè, una funzione statica che otterrebbe un oggetto Type come parametro (implicito) in base a qualsiasi sottoclasse da cui è stato utilizzato.

Un esempio di quello che voglio, approssimativamente, è

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) 

i risultati attesi essendo

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.)

risposta

1

In linea di principio, si potrebbe scrivere qualcosa del genere:

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

    public int ID { get; set; } 
} 

Poi si potrebbe scrivere var p = Base.Get<Puppy>(10). Oppure, se ti sentissi masochista, potresti scrivere Puppy.Get<Puppy>(10) o anche Kitty.Get<Puppy>;) In tutti i casi, devi passare esplicitamente il tipo, non implicitamente.

In alternativa, questo funziona anche:

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> 
{ 
} 

Hai ancora bisogno di passare il tipo indietro fino alla classe di base, che permette di scrivere Puppy.Get(10) come previsto.

Ma ancora, c'è un motivo per scriverlo così quando var p = new Puppy(10) è altrettanto conciso e più idiomatico? Probabilmente no.

2

A seconda del contesto, si sia voluto generici o metodi virtuali.

0

Questo è equivalente ai metodi di classe in Object Pascal. (Un'implementazione .Net sarebbe l'oxygene di RemObject).

Tuttavia, mentre i riferimenti di classe e quindi i metodi di classe virtuale o i metodi apparentemente statici che possono accedere a uno stato a livello di classe sono carini nella piattaforma originale, non penso abbiano molto senso per .Net o C#.

Ho anche programmato in Oxygene per diversi anni e non ho mai avuto bisogno di riferimenti di classe.

Non perché non sapevo come usarli. Nella piattaforma "originale" ObjectPascal, nativo Delphi, li ho usati tutti il tempo. Ma perché .Net e il BCL non hanno alcun supporto reale per loro, quindi non hai alcun vantaggio usandoli. Mentre piattaforme come Python o Delphi nativi li supportano nelle loro librerie.

Ovviamente non si desidera un metodo statico, ciò che si desidera è qualcosa che può avere lo stato e/o supporta l'ereditarietà. Quindi, o le fabbriche, o nel tuo caso un costruttore potrebbe andare bene pure.

0

Poiché C# viene compilato staticamente, una chiamata a Puppy.get() viene risolta in fase di compilazione, ad es. è noto per indicare Base.get() e ciò significa che il CIL generato (Common Intermediate Language) avrà un'istruzione di chiamata a 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 
}