2012-01-08T20:03:14の更新内容

programming/netfx/comparison/1_equation/index.wiki.txt

current previous
7,7 7,7
 

        

        
 
Object.Equalsメソッドを使うことで二つのオブジェクトが等しいかどうか単純な比較を行うことが出来ますが、どのような時に等しいとみなすか定義することが必要になる場合があります。
Object.Equalsメソッドを使うことで二つのオブジェクトが等しいかどうか単純な比較を行うことが出来ますが、どのような時に等しいとみなすか定義することが必要になる場合があります。
 

        

        
~
ここでは、オブジェクトの等価性を定義したり比較するためのインターフェイスであるIEquatable・IEqualityComparerと、関連するクラスについて見ていきます。 また、等価演算子のオーバーロードとこれらのインターフェイスの実装についても触れています。
ここでは、オブジェクトの等価性を定義したり比較するためのインターフェイスであるIEquatable・IEqualityComparerと、関連するクラスについて見ていきます。
 

        

        
 
#googleadunit(banner)
#googleadunit(banner)
 

        

        
748,391 748,5
 
Charlie    => mailto:charlie2@mail.example.com
Charlie    => mailto:charlie2@mail.example.com
 
}}
}}
 

        

        
+
----
+

          
+
*等価演算子のオーバーロードとインターフェイスの実装 [#OperatorOverloading]
+
ここまでで解説してきたインターフェースで実装されるEqualsメソッドは、''=='', ''!=''(''<>'') といった等価・不等価演算子の役割と似たものですが、両者は全く独立したものであり、このインターフェイスを実装したからといって等価演算子を用いた比較が出来るようになるわけではありません。 等価演算子を用いて比較するには、別途演算子をオーバーロードしなければなりません。 また逆に、等価演算子・不等価演算子をオーバーロードしたからといってList.Containsメソッドで要素の有無をチェックしたり、Dictionaryのキーとして使えるようになるというわけでもありません。 List.Containsメソッドで要素の有無を調べられるようにするには少なくともEqualsメソッド、Dictionaryのキーとして使用するにはEqualsメソッドとGetHashCodeメソッドの両方が適切に実装されている必要があります。
+

          
+
しかし、独自のクラスを構築する際、IEquatable<T>等による比較と等価演算子による比較の両方が出来るようにしたい場合も当然出てきます。
+

          
+
以下の例では、IEquatable<T>の実装と等価・不等価演算子のオーバーロードを行った構造体を作成しています。 この構造体では、等価演算子で等価性の定義と比較処理を実装し、IEquatable<T>.Equalsメソッドではオーバーロードした等価演算子を使って結果を返すようにしています。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+

          
+
struct Point : IEquatable<Point>
+
{
+
  int x, y;
+

          
+
  public Point(int x, int y)
+
  {
+
    this.x = x;
+
    this.y = y;
+
  }
+

          
+
  // IEquatable<Point>.Equalsの実装
+
  public bool Equals(Point other)
+
  {
+
    // 実際の比較はオーバーロードした等価演算子で行う
+
    return this == other;
+
  }
+

          
+
  // Object.Equalsをオーバーライド
+
  public override bool Equals(object obj)
+
  {
+
    if (obj is Point)
+
      // 型がPointならオーバーロードした等価演算子を使って比較
+
      return this == (Point)obj;
+
    else
+
      // 異なる型の場合はfalse
+
      return false;
+
  }
+

          
+
  // 等価演算子 == のオーバーロード
+
  public static bool operator == (Point l, Point r)
+
  {
+
    // フィールドxとyが等しければ二つのPointは等しいものとする
+
    return l.x == r.x && l.y == r.y;
+
  }
+

          
+
  // 不等価演算子 == のオーバーロード
+
  public static bool operator != (Point l, Point r)
+
  {
+
    // 等価演算子 == の結果を否定した結果を返す
+
    return !(l == r);
+
    // 当然、次のようにしても可
+
    //return l.x != r.x || l.y != r.y;
+
  }
+

          
+
  public override int GetHashCode()
+
  {
+
    return x.GetHashCode() ^ y.GetHashCode();
+
  }
+

          
+
  public override string ToString()
+
  {
+
    return string.Format("({0}, {1})", x, y);
+
  }
+
}
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    List<Point> list = new List<Point>(new Point[] {
+
      new Point(1, 0),
+
      new Point(0, 1),
+
      new Point(0, 0),
+
    });
+

          
+
    Point zero = new Point(0, 0);
+

          
+
    // オーバーロードした等価・不等価演算子のテスト
+
    Console.WriteLine("{0} {2} {1}", zero, list[0], zero == list[0] ? "==" : "!=");
+
    Console.WriteLine("{0} {2} {1}", zero, list[1], zero == list[1] ? "==" : "!=");
+
    Console.WriteLine("{0} {2} {1}", zero, list[2], zero != list[2] ? "!=" : "==");
+
    Console.WriteLine();
+

          
+
    // IEquatable<Point>.EqualsとオーバーライドしたObject.Equalsのテスト
+
    Console.WriteLine("{0} {2} {1}", zero, list[0], zero.Equals(list[0]) ? "Equals" : "Not Equals");
+
    Console.WriteLine("{0} {2} {1}", zero, list[2], zero.Equals(list[2]) ? "Equals" : "Not Equals");
+
    Console.WriteLine();
+
    Console.WriteLine("{0} {2} {1}", zero, 0, zero.Equals(0) ? "Equals" : "Not Equals");
+
    Console.WriteLine("{0} {2} {1}", zero, "null", zero.Equals(null) ? "Equals" : "Not Equals");
+
    Console.WriteLine();
+

          
+
    Console.WriteLine("Contains {0} = {1}", zero, list.Contains(zero));
+
    Console.WriteLine("Contains {0} = {1}", new Point(1, 1), list.Contains(new Point(1, 1)));
+
  }
+
}
+
}}
+

          
+
#prompt(実行結果){{
+
(0, 0) != (1, 0)
+
(0, 0) != (0, 1)
+
(0, 0) == (0, 0)
+

          
+
(0, 0) Not Equals (1, 0)
+
(0, 0) Equals (0, 0)
+

          
+
(0, 0) Not Equals 0
+
(0, 0) Not Equals null
+

          
+
Contains (0, 0) = True
+
Contains (1, 1) = False
+
}}
+

          
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Structure Point
+
  Implements IEquatable(Of Point)
+

          
+
  Dim x As Integer
+
  Dim y As Integer
+

          
+
  Public Sub New(ByVal x As Integer, ByVal y As Integer)
+
    MyClass.x = x
+
    MyClass.y = y
+
  End Sub
+

          
+
  ' IEquatable(Of Point).Equalsの実装
+
  Public Function Equals(ByVal other As Point) As Boolean Implements IEquatable(Of Point).Equals
+
    ' 実際の比較はオーバーロードした等価演算子で行う
+
    Return Me = other
+
  End Function
+

          
+
  ' Object.Equalsをオーバーライド
+
  Public Overrides Function Equals(ByVal obj As Object) As Boolean
+
    If TypeOf obj Is Point Then
+
      ' 型がPointならオーバーロードした等価演算子を使って比較
+
      Return Me = CType(obj, Point)
+
    Else
+
      ' 異なる型の場合はFalse
+
      Return False
+
    End If
+
  End Function
+

          
+
  ' 等価演算子 = のオーバーロード
+
  Public Shared Operator = (ByVal l As Point, ByVal r As Point) As Boolean
+
    ' フィールドxとyが等しければ二つのPointは等しいものとする
+
    Return l.x = r.x AndAlso l.y = r.y
+
  End Operator
+

          
+
  ' 等価演算子 <> のオーバーロード
+
  Public Shared Operator <> (ByVal l As Point, ByVal r As Point) As Boolean
+
    ' 等価演算子 = の結果を否定した結果を返す
+
    Return Not (l = r)
+
    ' 当然、次のようにしても可
+
    'Return l.x <> r.x OrElse l.y <> r.y
+
  End Operator
+

          
+
  Public Overrides Function GetHashCode() As Integer
+
    Return x.GetHashCode() Xor y.GetHashCode()
+
  End Function
+

          
+
  Public Overrides Function ToString() As String
+
    Return String.Format("({0}, {1})", x, y)
+
  End Function
+
End Structure
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim list As New List(Of Point)(New Point() { _
+
      New Point(1, 0), _
+
      New Point(0, 1), _
+
      New Point(0, 0) _
+
    })
+

          
+
    Dim zero As New Point(0, 0)
+

          
+
    ' オーバーロードした等価・不等価演算子のテスト
+
    Console.WriteLine("{0} {2} {1}", zero, list(0), If(zero = list(0), "=", "<>"))
+
    Console.WriteLine("{0} {2} {1}", zero, list(1), If(zero = list(1), "=", "<>"))
+
    Console.WriteLine("{0} {2} {1}", zero, list(2), If(zero <> list(2), "<>", "="))
+
    Console.WriteLine()
+

          
+
    ' IEquatable<Point>.EqualsとオーバーライドしたObject.Equalsのテスト
+
    Console.WriteLine("{0} {2} {1}", zero, list(0), If(zero.Equals(list(0)), "Equals", "Not Equals"))
+
    Console.WriteLine("{0} {2} {1}", zero, list(2), If(zero.Equals(list(2)), "Equals", "Not Equals"))
+
    Console.WriteLine()
+
    Console.WriteLine("{0} {2} {1}", zero, 0, If(zero.Equals(0), "Equals", "Not Equals"))
+
    Console.WriteLine("{0} {2} {1}", zero, "Nothing", If(zero.Equals(Nothing), "Equals", "Not Equals"))
+
    Console.WriteLine()
+

          
+
    Console.WriteLine("Contains {0} = {1}", zero, list.Contains(zero))
+
    Console.WriteLine("Contains {0} = {1}", New Point(1, 1), list.Contains(New Point(1, 1)))
+
  End Sub
+
End Class
+
}}
+

          
+
#prompt(実行結果){{
+
(0, 0) <> (1, 0)
+
(0, 0) <> (0, 1)
+
(0, 0) = (0, 0)
+

          
+
(0, 0) Not Equals (1, 0)
+
(0, 0) Equals (0, 0)
+

          
+
(0, 0) Not Equals 0
+
(0, 0) Equals Nothing
+

          
+
Contains (0, 0) = True
+
Contains (1, 1) = False
+
}}
+

          
+
#tabpage-end
+

          
+
なお、この例では構造体での等価演算子のオーバーロードを行いましたが、参照型でのオーバーロードを行う場合は ''x == y'' が参照の等価性(つまり同一のインスタンス)を表すのか、インスタンスの持つ値の等価性を表すのか曖昧になる場合がある点に注意が必要です。
+

          
+
もう一つ別の例を挙げます。 次の例において、Point構造体では等価・不等価演算子のオーバーロードのみを行い、キーとしての比較で必要となる処理はEqualityComparer<T>クラスを継承した別のクラスPointComparerで実装しています。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+

          
+
struct Point
+
{
+
  int x, y;
+

          
+
  public Point(int x, int y)
+
  {
+
    this.x = x;
+
    this.y = y;
+
  }
+

          
+
  // 等価演算子 == のオーバーロード
+
  public static bool operator == (Point l, Point r)
+
  {
+
    // フィールドxとyが等しければ二つのPointは等しいものとする
+
    return l.x == r.x && l.y == r.y;
+
  }
+

          
+
  // 不等価演算子 == のオーバーロード
+
  public static bool operator != (Point l, Point r)
+
  {
+
    // 等価演算子 == の結果を否定した結果を返す
+
    return !(l == r);
+
  }
+

          
+
  public override int GetHashCode()
+
  {
+
    return x.GetHashCode() ^ y.GetHashCode();
+
  }
+

          
+
  public override string ToString()
+
  {
+
    return string.Format("({0}, {1})", x, y);
+
  }
+
}
+

          
+
// Point構造体のためのEqualityComparer
+
class PointComparer : EqualityComparer<Point>
+
{
+
  public override bool Equals(Point a, Point b)
+
  {
+
    // オーバーロードした等価演算子を使って比較
+
    return a == b;
+
  }
+

          
+
  public override int GetHashCode(Point obj)
+
  {
+
    return obj.GetHashCode();
+
  }
+
}
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    // ある座標とその座標の名前のディクショナリ
+
    Dictionary<Point, string> dict = new Dictionary<Point, string>(new PointComparer());
+

          
+
    Point o = new Point(0, 0);
+
    Point a = new Point(1, 0);
+
    Point b = new Point(0, 1);
+
    Point c = new Point(1, 1);
+

          
+
    dict[o] = "O";
+
    dict[a] = "A";
+
    dict[b] = "B";
+

          
+
    Console.WriteLine("ContainsKey {0} = {1}", b, dict.ContainsKey(b));
+
    Console.WriteLine("ContainsKey {0} = {1}", c, dict.ContainsKey(c));
+

          
+
    foreach (KeyValuePair<Point, string> pair in dict)
+
    {
+
      Console.WriteLine("{0} => {1}", pair.Key, pair.Value);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Structure Point
+
  Dim x As Integer
+
  Dim y As Integer
+

          
+
  Public Sub New(ByVal x As Integer, ByVal y As Integer)
+
    MyClass.x = x
+
    MyClass.y = y
+
  End Sub
+

          
+
  ' 等価演算子 = のオーバーロード
+
  Public Shared Operator = (ByVal l As Point, ByVal r As Point) As Boolean
+
    ' フィールドxとyが等しければ二つのPointは等しいものとする
+
    Return l.x = r.x AndAlso l.y = r.y
+
  End Operator
+

          
+
  ' 等価演算子 <> のオーバーロード
+
  Public Shared Operator <> (ByVal l As Point, ByVal r As Point) As Boolean
+
    ' 等価演算子 = の結果を否定した結果を返す
+
    Return Not (l = r)
+
  End Operator
+

          
+
  Public Overrides Function GetHashCode() As Integer
+
    Return x.GetHashCode() Xor y.GetHashCode()
+
  End Function
+

          
+
  Public Overrides Function ToString() As String
+
    Return String.Format("({0}, {1})", x, y)
+
  End Function
+
End Structure
+

          
+
' Point構造体のためのEqualityComparer
+
Class PointComparer
+
  Inherits EqualityComparer(Of Point)
+

          
+
  Public Overrides Function Equals(ByVal a As Point, ByVal b As Point) As Boolean
+
    ' オーバーロードした等価演算子を使って比較
+
    Return a = b
+
  End Function
+

          
+
  Public Overrides Function GetHashCode(ByVal obj As Point) As Integer
+
    Return obj.GetHashCode()
+
  End Function
+
End Class
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' ある座標とその座標の名前のディクショナリ
+
    Dim dict As New Dictionary(Of Point, String)(New PointComparer())
+

          
+
    Dim o As New Point(0, 0)
+
    Dim a As New Point(1, 0)
+
    Dim b As New Point(0, 1)
+
    Dim c As New Point(1, 1)
+

          
+
    dict(o) = "O"
+
    dict(a) = "A"
+
    dict(b) = "B"
+

          
+
    Console.WriteLine("ContainsKey {0} = {1}", b, dict.ContainsKey(b))
+
    Console.WriteLine("ContainsKey {0} = {1}", c, dict.ContainsKey(c))
+

          
+
    For Each pair As KeyValuePair(Of Point, String) In dict
+
      Console.WriteLine("{0} => {1}", pair.Key, pair.Value)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
ContainsKey (0, 1) = True
+
ContainsKey (1, 1) = False
+
(0, 0) => O
+
(1, 0) => A
+
(0, 1) => B
+
}}
+

          
 
#navi(..)
#navi(..)
 

        

        

programming/netfx/comparison/0_comparison/index.wiki.txt

current previous
7,7 7,7
 

        

        
 
ソートを行うためには、並べ替えを行う個々の要素についてその大小関係を調べる必要があります。 また、独自に作成したクラスをソートするためには、その大小関係を定義する必要があります。
ソートを行うためには、並べ替えを行う個々の要素についてその大小関係を調べる必要があります。 また、独自に作成したクラスをソートするためには、その大小関係を定義する必要があります。
 

        

        
~
ここでは、コレクションとソートの基本と、大小関係を定義したり比較するためのインターフェイスであるIComparable・IComparerおよび関連するクラスについて見ていきます。 また、比較演算子のオーバーロードとこれらのインターフェイスの実装についても触れています。 ここで解説するソート方法やDictionaryのソートなどについては[[programming/netfx/sorting]]でも解説しているので、必要に応じて参照してください。
ここでは、コレクションとソートの基本と、大小関係を定義したり比較するためのインターフェイスであるIComparable・IComparerおよび関連するクラスについて見ていきます。 ここで解説するソート方法やDictionaryのソートなどについては[[programming/netfx/sorting]]でも解説しているので、必要に応じて参照してください。
 

        

        
 
#googleadunit(banner)
#googleadunit(banner)
 

        

        
2000,439 2000,5
 
井, 亜, 宇, 尾, 絵, 
井, 亜, 宇, 尾, 絵, 
 
}}
}}
 

        

        
+
----
+

          
+
*比較演算子のオーバーロードとインターフェイスの実装 [#OperatorOverloading]
+
ここまでで解説してきたインターフェースで実装されるCompareToメソッドやCompareメソッドは、''<'', ''>'', ''<='', ''>='' といった比較演算子の役割と似たものですが、両者は全く独立したものであり、このインターフェイスを実装したからといって比較演算子を用いた比較が出来るようになるわけではありません。 比較演算子を用いて比較するには、別途演算子をオーバーロードしなければなりません。 また逆に、比較演算子をオーバーロードしたからといってソートが出来るようになるというわけでもありません。 ソートするには型がIComparable<T>やIComparableなどのインターフェイスを実装している必要があります。
+

          
+
しかし、独自のクラスを構築する際、IComparable<T>等による比較(さらにソート)と比較演算子による比較の両方が出来るようにしたい場合も当然出てきます。
+

          
+
以下の例では、IComparable<T>の実装と比較演算子のオーバーロードを行ったクラスを作成しています。 このクラスでは、まずIComparable<T>で大小関係の定義と比較処理を実装し、オーバーロードした比較演算子ではIComparable<T>.CompareToを呼び出してその結果を使うようにしています。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Account : IComparable<Account>
+
{
+
  int id;
+
  string name;
+

          
+
  public Account(int id, string name)
+
  {
+
    this.id = id;
+
    this.name = name;
+
  }
+

          
+
  // IComparable<Account>.CompareToの実装
+
  public int CompareTo(Account other)
+
  {
+
    // 引数がnullの場合はArgumentNullExceptionをスローする
+
    if (other == null) throw new ArgumentNullException("other");
+

          
+
    // フィールドidの値の大小関係をCompareToの戻り値とする
+
    return this.id - other.id;
+
  }
+

          
+
  // 比較演算子 < のオーバーロード
+
  public static bool operator < (Account x, Account y)
+
  {
+
    // 被比較対象がnullの場合はArgumentNullExceptionをスローする
+
    if (x == null) throw new ArgumentNullException("x");
+

          
+
    // IComparable<Account>.CompareToの実装を使って比較した結果を返す
+
    return x.CompareTo(y) < 0;
+
  }
+

          
+
  // 比較演算子 <= のオーバーロード
+
  public static bool operator <= (Account x, Account y)
+
  {
+
    // 被比較対象がnullの場合はArgumentNullExceptionをスローする
+
    if (x == null) throw new ArgumentNullException("x");
+

          
+
    // IComparable<Account>.CompareToの実装を使って比較した結果を返す
+
    return x.CompareTo(y) <= 0;
+
  }
+

          
+
  // 比較演算子 > のオーバーロード
+
  public static bool operator > (Account x, Account y)
+
  {
+
    // 左辺と右辺を入れ替え比較演算子 < を使って結果を返す
+
    return y < x;
+
    // 比較演算子 <= の結果を逆転して返すやり方でも可
+
    //return !(x <= y);
+
  }
+

          
+
  // 比較演算子 >= のオーバーロード
+
  public static bool operator >= (Account x, Account y)
+
  {
+
    // 左辺と右辺を入れ替え比較演算子 <= を使って結果を返す
+
    return y <= x;
+
    // 比較演算子 < の結果を逆転して返すやり方でも可
+
    //return !(x < y);
+
  }
+

          
+
  public override string ToString()
+
  {
+
    return string.Format("{0}:{1}", id, name);
+
  }
+
}
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    // オーバーロードした比較演算子のテスト
+
    Account x = new Account(0, "Charlie");
+
    Account y = new Account(1, "Eve");
+
    Account z = new Account(1, "Alice");
+

          
+
    // 異なる値の場合
+
    Console.WriteLine("{0} {2} {1}", x, y, x <  y ? "<"  : ">=");
+
    Console.WriteLine("{0} {2} {1}", x, y, x <= y ? "<=" : ">");
+
    Console.WriteLine("{0} {2} {1}", x, y, x >  y ? ">"  : "<=");
+
    Console.WriteLine("{0} {2} {1}", x, y, x >= y ? ">=" : "<");
+
    Console.WriteLine();
+

          
+
    // 同値の場合
+
    Console.WriteLine("{0} {2} {1}", y, z, y <  z ? "<"  : ">=");
+
    Console.WriteLine("{0} {2} {1}", y, z, y <= z ? "<=" : ">");
+
    Console.WriteLine("{0} {2} {1}", y, z, y >  z ? ">"  : "<=");
+
    Console.WriteLine("{0} {2} {1}", y, z, y >= z ? ">=" : "<");
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Account
+
  Implements IComparable(Of Account)
+

          
+
  Dim id As Integer
+
  Dim name As String
+

          
+
  Public Sub New(ByVal id As Integer, ByVal name As String)
+
    MyClass.id = id
+
    MyClass.name = name
+
  End Sub
+

          
+
  ' IComparable(Of Account).CompareToの実装
+
  Public Function CompareTo(ByVal other As Account) As Integer Implements IComparable(Of Account).CompareTo
+
    ' 引数がNothingの場合はArgumentNullExceptionをスローする
+
    If other Is Nothing Then Throw New ArgumentNullException("other")
+

          
+
    ' フィールドidの値の大小関係をCompareToの戻り値とする
+
    Return MyClass.id - other.id
+
  End Function
+

          
+
  ' 比較演算子 < のオーバーロード
+
  Public Shared Operator < (ByVal x As Account, ByVal y As Account) As Boolean
+
    ' 被比較対象がNothingの場合はArgumentNullExceptionをスローする
+
    If x Is Nothing Then Throw New ArgumentNullException("x")
+

          
+
    ' IComparable(Of Account).CompareToの実装を使って比較した結果を返す
+
    Return x.CompareTo(y) < 0
+
  End Operator
+

          
+
  ' 比較演算子 <= のオーバーロード
+
  Public Shared Operator <= (ByVal x As Account, ByVal y As Account) As Boolean
+
    ' 被比較対象がNothingの場合はArgumentNullExceptionをスローする
+
    If x Is Nothing Then Throw New ArgumentNullException("x")
+

          
+
    ' IComparable(Of Account).CompareToの実装を使って比較した結果を返す
+
    Return x.CompareTo(y) <= 0
+
  End Operator
+

          
+
  ' 比較演算子 > のオーバーロード
+
  Public Shared Operator > (ByVal x As Account, ByVal y As Account) As Boolean
+
    ' 左辺と右辺を入れ替え比較演算子 < を使って結果を返す
+
    'Return y < x
+
    ' 比較演算子 <= の結果を逆転して返すやり方でも可
+
    Return Not (x <= y)
+
  End Operator
+

          
+
  ' 比較演算子 >= のオーバーロード
+
  Public Shared Operator >= (ByVal x As Account, ByVal y As Account) As Boolean
+
    ' 左辺と右辺を入れ替え比較演算子 <= を使って結果を返す
+
    'Return y <= x
+
    ' 比較演算子 < の結果を逆転して返すやり方でも可
+
    Return Not (x < y)
+
  End Operator
+

          
+
  Public Overrides Function ToString() As String
+
    Return String.Format("{0}:{1}", id, name)
+
  End Function
+
End Class
+

          
+
Class Sample
+
  Shared Sub Main()
+
    ' オーバーロードした比較演算子のテスト
+
    Dim x As New Account(0, "Charlie")
+
    Dim y As New Account(1, "Eve")
+
    Dim z As New Account(1, "Alice")
+

          
+
    ' 異なる値の場合
+
    Console.WriteLine("{0} {2} {1}", x, y, If(x <  y, "<",  ">="))
+
    Console.WriteLine("{0} {2} {1}", x, y, If(x <= y, "<=", ">"))
+
    Console.WriteLine("{0} {2} {1}", x, y, If(x >  y, ">",  "<="))
+
    Console.WriteLine("{0} {2} {1}", x, y, If(x >= y, ">=", "<"))
+
    Console.WriteLine()
+

          
+
    ' 同値の場合
+
    Console.WriteLine("{0} {2} {1}", y, z, If(y <  z, "<",  ">="))
+
    Console.WriteLine("{0} {2} {1}", y, z, If(y <= z, "<=", ">"))
+
    Console.WriteLine("{0} {2} {1}", y, z, If(y >  z, ">",  "<="))
+
    Console.WriteLine("{0} {2} {1}", y, z, If(y >= z, ">=", "<"))
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
0:Charlie < 1:Eve
+
0:Charlie <= 1:Eve
+
0:Charlie <= 1:Eve
+
0:Charlie < 1:Eve
+

          
+
1:Eve >= 1:Alice
+
1:Eve <= 1:Alice
+
1:Eve <= 1:Alice
+
1:Eve >= 1:Alice
+
}}
+

          
+
なお、この例ではnull/Nothingと比較しようとした場合はArgumentNullExceptionをスローするようにしていますが、文字列型(string)のようにnull/Nothingは他のすべての値よりも小さいというように実装することも出来ます。
+

          
+
もう一つ別の例を挙げます。 次の例において、Accountクラスでは比較演算子のオーバーロードのみを行い、ソートに必要となる処理はComparer<T>クラスを継承した別のクラスAccountComparerで実装しています。
+

          
+
#tabpage(C#)
+
#code(cs){{
+
using System;
+
using System.Collections.Generic;
+

          
+
class Account
+
{
+
  int id;
+
  string name;
+

          
+
  public Account(int id, string name)
+
  {
+
    this.id = id;
+
    this.name = name;
+
  }
+

          
+
  // 比較演算子 < のオーバーロード
+
  public static bool operator < (Account x, Account y)
+
  {
+
    // 被比較対象・比較対象がnullの場合はArgumentNullExceptionをスローする
+
    if (x == null) throw new ArgumentNullException("x");
+
    if (y == null) throw new ArgumentNullException("y");
+

          
+
    // フィールドidの値の大小関係に基づいて結果を返す
+
    return x.id < y.id;
+
  }
+

          
+
  // 比較演算子 <= のオーバーロード
+
  public static bool operator <= (Account x, Account y)
+
  {
+
    // 被比較対象・比較対象がnullの場合はArgumentNullExceptionをスローする
+
    if (x == null) throw new ArgumentNullException("x");
+
    if (y == null) throw new ArgumentNullException("y");
+

          
+
    // フィールドidの値の大小関係に基づいて結果を返す
+
    return x.id <= y.id;
+
  }
+

          
+
  // 比較演算子 > のオーバーロード
+
  public static bool operator > (Account x, Account y)
+
  {
+
    // 左辺と右辺を入れ替え比較演算子 < を使って結果を返す
+
    return y < x;
+
    // 比較演算子 <= の結果を逆転して返すやり方でも可
+
    //return !(x <= y);
+
  }
+

          
+
  // 比較演算子 >= のオーバーロード
+
  public static bool operator >= (Account x, Account y)
+
  {
+
    // 左辺と右辺を入れ替え比較演算子 <= を使って結果を返す
+
    return y <= x;
+
    // 比較演算子 < の結果を逆転して返すやり方でも可
+
    //return !(x < y);
+
  }
+

          
+
  public override string ToString()
+
  {
+
    return string.Format("{0}:{1}", id, name);
+
  }
+
}
+

          
+
// Accountクラスを並べ替えるComparer
+
class AccountComparer : Comparer<Account>
+
{
+
  public override int Compare(Account x, Account y)
+
  {
+
    // オーバーロードした比較演算子を使って比較
+
    if (x < y)
+
      return -1;
+
    else if (x > y)
+
      return 1;
+
    else // if (x == y)
+
      return 0;
+
  }
+
}
+

          
+
class Sample
+
{
+
  static void Main()
+
  {
+
    Account[] arr = new Account[] {
+
      new Account(1, "Eve"),
+
      new Account(4, "Dave"),
+
      new Account(2, "Alice"),
+
      new Account(0, "Charlie"),
+
      new Account(3, "Bob"),
+
    };
+

          
+
    Console.WriteLine("[before sort]");
+

          
+
    Print(arr);
+

          
+
    Console.WriteLine("[after sort]");
+

          
+
    // AccountComparerを使ってソート
+
    Array.Sort(arr, new AccountComparer());
+

          
+
    Print(arr);
+
  }
+

          
+
  static void Print(IEnumerable<Account> c)
+
  {
+
    foreach (Account e in c)
+
    {
+
      Console.WriteLine(e);
+
    }
+
  }
+
}
+
}}
+
#tabpage(VB)
+
#code(vb){{
+
Imports System
+
Imports System.Collections.Generic
+

          
+
Class Account
+
  Dim id As Integer
+
  Dim name As String
+

          
+
  Public Sub New(ByVal id As Integer, ByVal name As String)
+
    MyClass.id = id
+
    MyClass.name = name
+
  End Sub
+

          
+
  ' 比較演算子 < のオーバーロード
+
  Public Shared Operator < (ByVal x As Account, ByVal y As Account) As Boolean
+
    ' 被比較対象・比較対象がnullの場合はArgumentNullExceptionをスローする
+
    If x Is Nothing Then Throw New ArgumentNullException("x")
+
    If y Is Nothing Then Throw New ArgumentNullException("y")
+

          
+
    ' フィールドidの値の大小関係に基づいて結果を返す
+
    Return x.id < y.id
+
  End Operator
+

          
+
  ' 比較演算子 <= のオーバーロード
+
  Public Shared Operator <= (ByVal x As Account, ByVal y As Account) As Boolean
+
    ' 被比較対象がNothingの場合はArgumentNullExceptionをスローする
+
    If x Is Nothing Then Throw New ArgumentNullException("x")
+
    If y Is Nothing Then Throw New ArgumentNullException("y")
+

          
+
    ' フィールドidの値の大小関係に基づいて結果を返す
+
    Return x.id <= y.id
+
  End Operator
+

          
+
  ' 比較演算子 > のオーバーロード
+
  Public Shared Operator > (ByVal x As Account, ByVal y As Account) As Boolean
+
    ' 左辺と右辺を入れ替え比較演算子 < を使って結果を返す
+
    'Return y < x
+
    ' 比較演算子 <= の結果を逆転して返すやり方でも可
+
    Return Not (x <= y)
+
  End Operator
+

          
+
  ' 比較演算子 >= のオーバーロード
+
  Public Shared Operator >= (ByVal x As Account, ByVal y As Account) As Boolean
+
    ' 左辺と右辺を入れ替え比較演算子 <= を使って結果を返す
+
    'Return y <= x
+
    ' 比較演算子 < の結果を逆転して返すやり方でも可
+
    Return Not (x < y)
+
  End Operator
+

          
+
  Public Overrides Function ToString() As String
+
    Return String.Format("{0}:{1}", id, name)
+
  End Function
+
End Class
+

          
+
' Accountクラスを並べ替えるComparer
+
Class AccountComparer
+
  Inherits Comparer(Of Account)
+

          
+
  Public Overrides Function Compare(ByVal x As Account, ByVal y As Account) As Integer
+
    ' オーバーロードした比較演算子を使って比較
+
    If x < y Then
+
      Return -1
+
    Else If x > y Then
+
      Return 1
+
    Else ' If x = y Then
+
      Return 0
+
    End If
+
  End Function
+
End Class
+

          
+
Class Sample
+
  Shared Sub Main()
+
    Dim arr() As Account = New Account() { _
+
      New Account(1, "Eve"), _
+
      New Account(4, "Dave"), _
+
      New Account(2, "Alice"), _
+
      New Account(0, "Charlie"), _
+
      New Account(3, "Bob") _
+
    }
+

          
+
    Console.WriteLine("[before sort]")
+

          
+
    Print(arr)
+

          
+
    Console.WriteLine("[after sort]")
+

          
+
    ' AccountComparerを使ってソート
+
    Array.Sort(arr, New AccountComparer())
+

          
+
    Print(arr)
+
  End Sub
+

          
+
  Shared Sub Print(ByVal c As IEnumerable(Of Account))
+
    For Each e As Account In c
+
      Console.WriteLine(e)
+
    Next
+
  End Sub
+
End Class
+
}}
+
#tabpage-end
+

          
+
#prompt(実行結果){{
+
[before sort]
+
1:Eve
+
4:Dave
+
2:Alice
+
0:Charlie
+
3:Bob
+
[after sort]
+
0:Charlie
+
1:Eve
+
2:Alice
+
3:Bob
+
4:Dave
+
}}
+

          
 
#navi(..)
#navi(..)