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

40

我有一个枚举类型,希望为其定义><>=<=运算符。我知道这些运算符是基于枚举类型隐式创建的(根据文档),但我想显式定义这些运算符(为了更清晰、更可控、了解如何做等等)。

我希望可以这样做:

public enum SizeType
{
    Small = 0,
    Medium = 1,
    Large = 2,
    ExtraLarge = 3
}

public SizeType operator >(SizeType x, SizeType y)
{

}

但这似乎不起作用("unexpected token")...这可能吗?因为有隐式定义的操作符,所以似乎应该可以。有什么建议吗?


1
对于那些不仔细阅读问题并至少阅读评论的人,**`>, <, >=和<=运算符是根据枚举类型隐式创建的** - 所以也许您不需要任何自定义内容。我写了整个包装结构,然后意识到事情在没有它的情况下也能正常工作。 - psfinaki
5个回答

37

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


1
这很令人失望,那他们怎么隐式地实现了呢?看起来似乎没有办法,但是我想如果可以隐式地完成它,那么肯定有一种显式的方式可以实现。我猜错了。感谢您提供的信息。 - ChrisHDog
1
它们不行。也没有隐式的方法。你不能为枚举重载运算符。 - Mehrdad Afshari
1
啊哈。我以为你的意思是你可以为枚举类型实现一个隐式运算符。你所指的陈述中的关键词是“预定义”。事实上,你不能为枚举类型定义任何自定义运算符实现。 - Mehrdad Afshari
这是一个很烦人的 bug,找起来真的很麻烦。 - Robbie

26

正如其他人之前所提到的,不能在枚举上重写运算符,但可以在结构体上这样做。请参考以下示例。如果有帮助,请告诉我:

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 语句中使用,而结构体则不行。 - Mike de Klerk
@MikedeKlerk 这在C# 7.0中有所改变 https://blogs.msdn.microsoft.com/dotnet/2016/08/24/whats-new-in-csharp-7-0/ - MaLiN2223

21

根据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 -- Method in enum
***** FAILURE *****

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


15

正如Mehrdad所说,你不能在枚举本身上这样做。但是你可以创建一些扩展方法来操作你的枚举,这会让它看起来像是枚举上的方法。

static bool IsLessThan(this SizeType first, SizeType second) {
}

4

你不能重写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


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