如何在 C# 中为枚举重载运算符?

Posted

技术标签:

【中文标题】如何在 C# 中为枚举重载运算符?【英文标题】:How do I overload an operator for an enumeration in C#? 【发布时间】:2010-11-24 06:11:15 【问题描述】:

我有一个枚举类型,我想为它定义><>=<= 运算符。我知道这些运算符是基于枚举类型隐式创建的(根据documentation),但我想明确定义这些运算符(为了清楚起见,为了控制,知道如何做等等...... )

我希望我可以这样做:

public enum SizeType

    Small = 0,
    Medium = 1,
    Large = 2,
    ExtraLarge = 3


public SizeType operator >(SizeType x, SizeType y)



但这似乎不起作用(“意外令牌”)......这可能吗?似乎应该如此,因为有隐含定义的运算符。有什么建议吗?

【问题讨论】:

对于那些不认真阅读问题并至少阅读 cmets 的人,>, <, >=, and <= operators are implicitly created on the basis of the enumerated type - 所以也许你不需要任何自定义的东西。我编写了整个包装结构,然后意识到没有它也能正常工作。 【参考方案1】:

你不能那样做。您只能为您定义的类和结构提供重载运算符——并且至少一个参数应该是类或结构本身的类型。也就是说,您可以声明一个重载的加法运算符,将MyClass 添加到MyEnum,但您永远不能使用两个MyEnum 值来实现。

【讨论】:

这令人失望,那他们是如何隐含地做到这一点的呢?似乎没有办法,但我想如果你可以隐式地做到这一点,那么应该有一种方法可以显式地做到这一点。我猜不会。感谢您提供信息。 他们没有。也没有 implicit 方式。您根本不能为枚举重载运算符。 根据:msdn.microsoft.com/en-us/library/aa664726(VS.71).aspx ...“每个枚举类型都隐含地提供了以下预定义的比较运算符:”...我只是希望有一种方法可以明确地提供类似的比较运算符。所以不是一个重载运算符,而是类似的东西。 啊哈。我以为你的意思是你可以为枚举实现一个隐式运算符。您提到的语句中的关键字是predefined。问题是,您不能为枚举定义任何自定义运算符实现。 嗯,这是一个令人讨厌的错误。【参考方案2】:

正如 Mehrdad 所说,您不能在枚举本身上这样做。但是,您可以制作一些适用于您的枚举的扩展方法。这将使它看起来像枚举上的方法。

static bool IsLessThan(this SizeType first, SizeType second) 

【讨论】:

【参考方案3】:

如前所述,不能覆盖 Enums 上的运算符,但可以在 struct 上覆盖。请参阅下面的示例。如果有帮助,请告诉我:

public struct SizeType

    private int InternalValue  get; set; 

    public static readonly int Small = 0;
    public static readonly int Medium = 1;
    public static readonly int Large = 2;
    public static readonly int ExtraLarge = 3;

    public override bool Equals(object obj)
    
        SizeType otherObj = (SizeType)obj;
        return otherObj.InternalValue.Equals(this.InternalValue);
    

    public static bool operator >(SizeType left, SizeType right)
    
        return (left.InternalValue > right.InternalValue);
    

    public static bool operator <(SizeType left, SizeType right)
    
        return (left.InternalValue < right.InternalValue);
    

    public static implicit operator SizeType(int otherType)
    
        return new SizeType
        
            InternalValue = otherType
        ;
    


public class test11

    void myTest()
    
        SizeType smallSize = SizeType.Small;
        SizeType largeType = SizeType.Large;
        if (smallSize > largeType)
        
            Console.WriteLine("small is greater than large");
        
    

【讨论】:

枚举可以在 switch 语句中使用,而结构不能。 @MikedeKlerk 这个在 C# 7.0 中的半改动 blogs.msdn.microsoft.com/dotnet/2016/08/24/…【参考方案4】:

根据 ECMA-335 公共语言基础架构:

CTS 支持枚举(也称为枚举类型)、 现有类型的备用名称。为了匹配 签名,枚举不应与基础类型相同。 但是,枚举的实例应可分配给基础 类型,反之亦然。也就是说,没有强制转换(参见 §8.3.3)或强制(参见 §8.3.2) 需要从枚举转换为基础类型, 从基础类型到枚举也不需要它们。一个枚举是 比真正的类型更受限制,如下所示:它应 只有一个实例字段,并且该字段的类型定义 枚举的基础类型。

它不应有任何自己的方法。 它应从 System.Enum 派生(请参阅分区 IV 库 - 内核包)。 它不应实现自己的任何接口。 它不应有任何自己的属性或事件。 它不应有任何静态字段,除非它们是文字的。 (参见第 8.6.1.2 节)

假设我们有以下 IL 代码:

.class public auto ansi sealed Test.Months extends [mscorlib]System.Enum

  .field public specialname rtspecialname int32 value__
  .field public static literal valuetype Test.Months January = int32(0x00000001)
  .field public static literal valuetype Test.Months February = int32(0x00000002)
  .field public static literal valuetype Test.Months March = int32(0x00000003)
  // ...

  .method public hidebysig specialname static valuetype Test.Months 
  op_Increment(valuetype Test.Months m) cil managed
  
    .maxstack 8

    IL_0000: ldarg.0
    IL_0001: ldc.i4.s 10
    IL_0003: add
    IL_0004: ret
  
 // end of class Test.Months

MSIL 编译器 (ilasm.exe) 会产生以下错误:

error -- 枚举中的方法
***** 失败 *****

所以即使编辑 IL 代码,我们也不能重载枚举运算符 ;)

【讨论】:

【参考方案5】:

无法覆盖 compareto 方法,但可以添加扩展方法:

<Runtime.CompilerServices.Extension()> 
Public Function Compare(ByVal obj1 As EnumType, ByVal obj2 As EnumType) as integer
    Dim CompareResults as integer = 0
    'some code  here to do your comparison
    Return CompareResults
End Sub

然后执行如下:

IntegerResult = myEnum.Compare(otherEnum)

来自http://msdn.microsoft.com/en-us/library/bb384936.aspx

【讨论】:

以上是关于如何在 C# 中为枚举重载运算符?的主要内容,如果未能解决你的问题,请参考以下文章

枚举类中的 c++ 运算符重载

C#中的运算符重载

c++ 转换运算符重载、枚举、整数和字符

为什么我应该在结构而不是类中为priority_queue重载()运算符?

C#运算符重载---逐步地分析与理解

了解下C# 运算符重载