『スラスラわかるC#』第6章 読書メモ

スラスラわかるC# (Beginner’s Best Guide to Programmin)

演算子オーバーロード

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]);
        }
    }
}

コメントを残す

コメントを残す