Как перегрузить оператор для перечисления в C #? - PullRequest
33 голосов
/ 31 августа 2009

У меня есть перечислимый тип, для которого я хотел бы определить операторы >, <, >= и <=. Я знаю, что эти операторы косвенно создаются на основе перечислимого типа (согласно документации ), но я хотел бы явно определить эти операторы (для ясности, для контроля, чтобы знать, как это сделать, и т.д ...)

Я надеялся, что смогу сделать что-то вроде:

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

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

}

Но это, похоже, не работает («неожиданный токен») ... возможно ли это? Похоже, так и должно быть, поскольку существуют имплицитно определенные операторы. Есть предложения?

Ответы [ 5 ]

32 голосов
/ 31 августа 2009

Вы не можете этого сделать. Вы можете предоставить перегруженные операторы только для определенных вами классов и структур - и хотя бы один из параметров должен относиться к типу класса или самой структуры. То есть вы можете объявить перегруженный оператор сложения, который добавляет MyClass к MyEnum, но вы никогда не сможете сделать это с двумя значениями MyEnum.

23 голосов
/ 17 сентября 2009

Как уже упоминалось ранее, нельзя переопределять операторы в 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");
        }
    }
}
17 голосов
/ 26 октября 2011

Согласно общеязыковой инфраструктуре 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 compiler (ilasm.exe) выдаст следующую ошибку:

error -- Method in enum
***** FAILURE *****

Так что мы не можем перегрузить оператор enum, даже редактируя код IL;)

11 голосов
/ 31 августа 2009

Как говорит Мерадад, вы не можете сделать это на самом перечислении. Однако вы можете создать несколько методов расширения, которые будут работать с вашим перечислением. Это сделает его похожим на методы перечисления.

static bool IsLessThan(this SizeType first, SizeType second) {
}
3 голосов
/ 09 апреля 2013

Вы не можете переопределить метод сравнения, но вы можете добавить метод расширения:

<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

...