扩展方法是向枚举添加函数的唯一方式吗?

8

我有一个 Direction 枚举:

Public Enum Direction
    Left
    Right
    Top
    Bottom
End Enum

有时候我需要得到反向结果,所以写成这样似乎更好:
SomeDirection.Inverse()

但是我不能在枚举上放置方法!然而,我可以为其添加一个扩展方法(VS2008+)。

在VB中,扩展方法必须在模块内部。我真的不太喜欢模块,我正在尝试编写一个(适度)简单的类,可以在单个文件中共享,并将其插入其他项目中。

模块只能驻留在文件/命名空间级别,因此现在我在文件底部有一个模块:

Public Class MyClass
    '...'
End Class

Public Module Extensions
    <Extension()> _
    Public Function Inverse(ByVal dir As Direction) As Direction
        '...'
    End Function
End Module

它能够正常工作,"如果没有问题,就不要修复它",但我很想知道是否有更好的方法来减少样板代码。也许在.NET 4中会有更好的方法吗?
最后,我知道我可以编写一个像枚举一样行为的结构,但那似乎更加反向。

1
你所做的是绝对正确的。微软也提出了同样的建议:http://msdn.microsoft.com/en-us/library/bb383974.aspx。 - VinayC
我明白了(好发现!),所以这一定是正确的方法。但我仍然不明白为什么我们不能在枚举上放置一个方法,这似乎不会破坏任何东西。 - Camilo Martin
2个回答

7

这确实是向枚举类型添加(伪造)方法的唯一途径。

请注意,在C#中,扩展方法将被定义在静态类上,但这只是一个微不足道的区别,主要是术语上的差别。


在VB中,类不能被声明为共享(静态)。据我所知,它们相当于模块。但由于扩展方法只是语法糖,用于静态方法,我不理解为什么需要将其放在不同的类中(因为静态方法可以存在于非静态类中)。 - Camilo Martin
一个扩展方法(在C#中)不能存在于非静态类中,请注意。 - Marc Gravell
我知道它不能,但我不理解背后的原因。 - Camilo Martin
在我看来,原因是它强制明确目的。实例类中的静态方法应与该类相关。(不一定非得如此,但在实例类中拥有与其无关的静态方法是一个非常糟糕的想法。)扩展方法的设计只能修改不同的类。因此,在包含扩展方法的类中允许实例方法是不明智的——按设计,这样的类将具有不相关的方法。 - Mike Rosenblum
就C#的枚举功能而言,我是同意的。正如John Skeet在《C#程序设计语言》第四版中所评论的那样:“这是Java比C#更具表现力的非常少见的领域之一。在Java中,枚举有更多的能力:一个枚举可以声明方法,然后为特定的值覆盖它们... C#语言(和框架)在未来的版本中支持将是非常受欢迎的。” - Mike Rosenblum

1

你可以创建一个类,它的行为类似于枚举,因为它具有静态只读属性,这些属性返回包含该值的类的实例。

例如,System.Drawing.Color 结构就是这样工作的(尽管内部值不是枚举);它具有像 Color.RedColor.White 这样的静态属性,以及实例属性和方法。


那将比仅使用模块更加繁琐。即使是类也不必要去模拟枚举 - 在结构中也可以完成相同的工作。但是,看到一个结构假装成枚举确实很奇怪。 - Camilo Martin
@Camilo Martin:是的,结构体也可以使用,但我建议使用类的原因是结构体的正确实现更加复杂。使用类而不是枚举可能看起来很奇怪,但另一方面,你可以在类本身中获得方法,而不是在一个单独的模块中。 - Guffa
为什么要复杂化?这个答案的代码看起来很简单:http://stackoverflow.com/questions/1395401/enum-extension-method-todatasource/1395439#1395439 - Camilo Martin
1
@Camilo Martin:这就是为什么结构体更难实现的一个例子;那段代码无法编译。即使修复了,它仍然不支持你认为理所当然的东西,比如“==”运算符。如果将其改为类,则可以正常工作(只需将私有静态属性更改为公共属性)。 - Guffa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接