2010-01-13 3 views
6

Есть ли способ сделать то, что classmethod делает в Python в C#?Стиль-стиль в стиле Python для C#?

То есть статическая функция, которая будет получать объект 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).

Однако, хотя ссылки на классы и, таким образом, методы виртуального класса или, по-видимому, статические методы, которые могут получить доступ к некоторому состоянию на уровне класса, хороши там, там оригинальная платформа, я не думаю, что они имеют смысл для .Net или C#.

Я использовал также программу в Oxygene в течение нескольких лет, и мне никогда не нужны ссылки на классы.

Не потому, что я не знал, как их использовать. В «оригинальной» платформе ObjectPascal, родном Delphi, я использовал их все время. Но поскольку .Net и BCL не имеют реальной поддержки для них, поэтому у вас нет никаких преимуществ, используя их. В то время как платформы, такие как python или native Delphi, поддерживают их в своих библиотеках.

Вы, очевидно, не хотите статический метод, то, что вы хотите, это то, что может иметь состояние и/или поддерживает наследование. Таким образом, либо фабрики, либо, в вашем случае, конструктор может быть прекрасен.

0

Поскольку C# статически компилируется, вызов Puppy.get() разрешен во время компиляции, например. это известно, чтобы указать на Base.get(), и это означает, что сгенерированный CIL (Common Intermediate Language) будет иметь инструкции вызова в 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 
} 
Смежные вопросы