web-dev-qa-db-ja.com

C#で列挙型の演算子をオーバーロードするにはどうすればよいですか?

><>=、および<=演算子を定義したい列挙型があります。これらの演算子は列挙型に基づいて暗黙的に作成されることを知っています( documentation に従って)が、これらの演算子を明示的に定義したいと思います(明確にするため、制御するため、それを行う方法を知るため) 、など...)

私は次のようなことができることを望んでいました:

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

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

}

しかし、これは機能しないようです(「予期しないトークン」)...これは可能ですか?暗黙的に定義された演算子があるので、それはそうであるように思われます。助言がありますか?

35
ChrisHDog

それはできません。定義できるのは、クラスと構造体のオーバーロードされた演算子のみです。少なくとも1つのパラメーターは、クラスまたは構造体自体の型である必要があります。つまり、canMyClassMyEnumに追加するオーバーロードされた追加演算子を宣言しますが、2つのMyEnum値を使用してこれを行うことはできません。

34
Mehrdad Afshari

前に述べたように、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");
        }
    }
}
24

ECMA-335 Common Language Infrastructureによると、

CTSは、既存のタイプの代替名である列挙型(列挙型とも呼ばれる)をサポートします。署名を照合するために、列挙型は基本となる型と同じであってはなりません。ただし、列挙型のインスタンスは、基になる型に割り当て可能であり、その逆も可能です。つまり、列挙型から基底型に変換するためにキャスト(§8.3.3を参照)や強制(§8.3.2を参照)を行う必要はなく、基底型から列挙型に変換する必要もありません。列挙型は、次のように、真の型よりもかなり制限されています。それは、インスタンスフィールドを1つだけ持つ必要があり、そのフィールドの型は、列挙型の基になる型を定義します。

  • 独自のメソッドはありません。
  • これはSystem.Enumから派生します(Partition IV Library – Kernel Packageを参照)。
  • 独自のインターフェースは実装しません。
  • 独自のプロパティやイベントがあってはなりません。
  • リテラルでない限り、静的フィールドはありません。 (§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)は、次のエラーを生成します。

エラー-列挙型のメソッド
 *****失敗*****

そのため、ILコードを編集しても、列挙演算子をオーバーロードできません;)

20
Wojteq

Mehrdadが言うように、列挙自体ではそれを行うことはできません。ただし、列挙型で機能する拡張メソッドをいくつか作成することもできます。これにより、列挙型のメソッドのようになります。

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

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

3
VoteCoffee