C#的Python风格的类方法?

时间:2010-01-13 17:35:02

标签: c# python class-method

有没有办法在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.)

5 个答案:

答案 0 :(得分:3)

我想你想看看泛型。

MSFT指南:

http://msdn.microsoft.com/en-us/library/ms379564(VS.80).aspx

答案 1 :(得分:2)

根据上下文,您可能需要泛型或虚拟方法。

答案 2 :(得分: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)同样简洁且更惯用时,是否有理由这样写呢?可能不是。

答案 3 :(得分:0)

这相当于Object Pascal中的类方法。 (a .Net实现将是RemObject的oxygene)。

然而,虽然类引用和虚拟类方法或看似静态的方法可以访问某些类级别的状态在原始平台上很好,但我认为它们对.Net或C#没有多大意义。

我曾经在Oxygene中编程好几年,我从不需要课程参考。

不是因为我不知道如何使用它们。在“原始”ObjectPascal平台,原生Delphi中,我用它们全部时间。 但是因为.Net和BCL对它们没有真正的支持,所以使用它们没有任何好处。而像python或本地Delphi这样的平台确实在它们的库中支持它们。

你显然不想要一个静态方法,你想要的是可以拥有状态和/或支持继承的东西。所以无论是工厂,还是在你的情况下,构造函数都可能没问题。

答案 4 :(得分: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
}