演算子オーバーロード
C#では、演算子をオーバーロードすることができる。演算子のオーバーロードにはoperator修飾子を使用しする。また、オーバーロードには以下の制約がある。
- public staticである必要がある
- 演算子の種類に応じて制約がある(例えば、+は必ず引数を2つ取る)
using System; namespace Sample { struct Point { private int _x; private int _y; public int X { get { return _x; } } public int Y { get { return _y; } } public Point(int x, int y) { _x = x; _y = y; } public static Point operator +(Point p, Point q) { return new Point(p.X + q.X, p.Y + q.Y); } public static Point operator -(Point p, Point q) { return new Point(p.X - q.X, p.Y - q.Y); } public override string ToString() { return string.Format("{0}, {1}", X, Y); } } class Program { static void Main(string[] args) { var p = new Point(1, 2); p += new Point(2, 3); Console.WriteLine(p); } } }
インクリメント・デクリメント
++及び–をオーバーロードする際には、自己書き換えをしないよう注意する。
using System;
namespace Sample
{
class Counter
{
public int Count { get; private set; }
public Counter() : this(0) { }
private Counter(int count) { Count = count; }
public static Counter operator++(Counter x)
{
return new Counter(x.Count + 1); // x を書き換えず、新しいインスタンスを作る
}
}
class Program
{
static void Main(string[] args)
{
var c = new Counter();
Console.WriteLine(c.Count);
++c;
Console.WriteLine(c.Count);
c++;
Console.WriteLine(c.Count);
}
}
}
true、false演算子と条件論理演算子
演算子オーバーロードを使用することで、bool型しか受け付けない場所でユーザー定義型を使えるようになる。
using System;
namespace Sample
{
struct IntBool
{
private int i;
public IntBool(int i) { this.i = (i == 0) ? 0 : 1; }
public static bool operator true(IntBool b)
{
Console.WriteLine("operator true");
return b.i != 0;
}
public static bool operator false(IntBool b)
{
Console.WriteLine("operator false");
return b.i == 0;
}
}
class Program
{
static void Main(string[] args)
{
var x = new IntBool(1);
if (x) {
Console.WriteLine("if true");
}
}
}
}
独自のキャスト定義
キャストのオーバーロードでは、implicit又はexplicitキーワードをつけて、暗黙的なキャストを許可するかを定義する必要がある。
using System;
namespace Sample
{
class X
{
// allow implicit casting
public static implicit operator Y(X x) { return new Y(); }
}
class Y
{
// disallow implicit casting
public static explicit operator X(Y x) { return new X(); }
}
class Program
{
static void Main(string[] args)
{
var x = new X();
var y = new Y();
Y xToY1 = (Y)x;
X yToX1 = (X)y;
Y xToY2 = x;
//X yToX2 = y; // Implicit casting of Y -> X is disallowed
}
}
}
コレクション初期化子
var x = new List<int> {1,2,3};
の、{}の部分をコレクション初期化子と呼ぶ。コレクション初期化子を使える条件は以下の通り。
- IEnumerableインターフェイスを実装している
- Addメソッドを持っている
using System;
using System.Collections;
namespace Sample
{
class CollectionInitializable : IEnumerable
{
public void Add(string item)
{
Console.WriteLine("{0} Added", item);
}
public IEnumerator GetEnumerator()
{
throw new NotImplementedException();
}
}
class Program
{
static void Main(string[] args)
{
var x = new CollectionInitializable { "a", "b", "c" };
}
}
}
インデクサー
ユーザー定義型に対して[]を使った添え字アクセスをするための構文をインデクサーと呼ぶ。添え字の型は整数型である必要はない。
using System; using System.Collections; namespace Sample { class RangedArray<T> { T[] array; int lower; public RangedArray(int lower, int length) { this.lower = lower; array = new T[length]; } // Define indexer public T this[int i] { set { this.array[i - lower] = value; } get { return this.array[i - lower]; } } } class Program { static void Main(string[] args) { var a = new RangedArray<int>(1, 3); a[1] = 2; a[2] = 4; Console.WriteLine(a[1]); } } }