C# 的 Python 风格类方法?

发布于 2024-08-17 17:32:26 字数 630 浏览 2 评论 0原文

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

(此处键盘上的代码相同。)

Is there a way to do what classmethod does in Python in C#?

That is, a static function that would get a Type object as an (implicit) parameter according to whichever subclass it's used from.

An example of what I want, approximately, is

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)

the expected output being

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

吃不饱 2024-08-24 17:32:26

我想你想看看泛型。

MSFT 指南:

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

I think you want to take a look at generics.

Guide from MSFT:

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

春庭雪 2024-08-24 17:32:26

原则上,您可以编写如下内容:

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(10)。或者,如果您感到受虐狂,您可以编写 Puppy.Get(10) 甚至 Kitty.Get ;) 在所有情况下,您都有显式而不是隐式地传递类型。

或者,这也有效:

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) 一样简洁且更惯用时,还有理由这样写吗?可能不会。

In principle, you could write something like this:

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

    public int ID { get; set; }
}

Then you could write var p = Base.Get<Puppy>(10). Or, if you were feeling masochistic, you could write Puppy.Get<Puppy>(10) or even Kitty.Get<Puppy> ;) In all cases, you have to pass in the type explicitly, not implicitly.

Alternatively, this works too:

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

You still need to pass the type back up to the base class, which allows you to write Puppy.Get(10) as expected.

But still, is there a reason to write it like that when var p = new Puppy(10) is just as concise and more idiomatic? Probably not.

甜尕妞 2024-08-24 17:32:26

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

Depending on the context, you either want generics or virtual methods.

江挽川 2024-08-24 17:32:26

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

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

我也曾在 Oxygene 中编程多年,而且我从不需要类引用。

不是因为我不知道如何使用它们。在“原始”ObjectPascal 平台、原生 Delphi 中,我一直使用它们。
但由于.Net和BCL对它们没有真正的支持,所以使用它们并没有任何优势。而像 python 或本机 Delphi 这样的平台确实在其库中支持它们。

您显然不想要静态方法,您想要的是可以具有状态和/或支持继承的方法。因此,无论是工厂,还是在您的情况下,构造函数也可能没问题。

This is equivalent to class methods in Object Pascal. (a .Net implementation would be RemObject's oxygene).

However, while class references and thus virtual class methods or seemingly static methods which can kinda access some class-level state are nice in there original platform, I don't think they make much sense for .Net or C#.

I used to also program in Oxygene for several years, and I never needed class references.

Not because I didn't know how to use them. In the "original" ObjectPascal platform, native Delphi, I used them all the time.
But because .Net and the BCL have no real support for them, so you do not have any advantages by using them. Whereas platforms like python or native Delphi do support them in their libraries.

You obviously do not want a static method, what you want is something that can have state and/or supports inheritance. So either factories, or in your case a constructor might be fine as well.

初雪 2024-08-24 17:32:26

由于 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
} 

Because C# is statically compiled, a call to Puppy.get() is resolved at compile time, eg. it's known to point to Base.get() and that means that the generated CIL (Common Intermediate Language) will have a call instruction to 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
} 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文