Look into C# Samples(Delegate) (1)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Test_Delegate
{
    //代表者宣言
    delegate int Sample(int x,int y);   

    class Class2
    {
        public static int methodMult(int x, int y)
        {
            return x * y;
        }
        public static int methodPlus(int x, int y)
        {
            return x + y;
        }
        public int method(int x, int y)
        {
            return (x + y) * 10;
        }
    }

    class Class3
    {
        public int methodPlus(int x, int y)
        {
            return x + y;
        }
    }

    abstract class ClassBase
    {
        public abstract int method(int x, int y);
    }

    class ClassMult : ClassBase
    {
        public override int method(int x, int y)
        {
            return x * y;
        }
    }

    class ClassPlus : ClassBase
    {
        public override int method(int x, int y)
        {
            return x + y;
        }
    }

    delegate void Sample2(string message);
    class Class4
    {
        private void outputMessage(string message)
        {
            Console.WriteLine(message);
        }
        //Note: Create a public method for delegate to access
        public Sample2 getDelegate()
        {
            return new Sample2(this.outputMessage);
        }
    }

    delegate void Sample3();
    class Class5
    {
        public void method1()
        {
            Console.WriteLine("method1 called");
        }
        public void method2()
        {
            Console.WriteLine("method2 called");
        }
    }

    class Class6
    {
        private string name;
        public Class6(string name)
        {
            this.name = name;
        }
        public void method()
        {
            Console.WriteLine(name);
        }
    }

    delegate void Sample4();
    delegate void Sample5();
    class Class7
    {
        public static void method()
        {
            Console.WriteLine("hihi");
        }
    }

    //--------------------------------------------
    class Program
    {
        public static void calc(int x, int y, Sample calcMethod)
        {
            int result = calcMethod(x, y);
            Console.WriteLine(result);
        }
        public static void calc2(int x, int y, ClassBase instance)
        {
            int result = instance.method(x, y);
            Console.WriteLine(result);
        }
        static void Main(string[] args)
        {
            //staticメソッドのためインスタンスいらない
            //Class2 instance = new Class2();
            //処理を一元化
            //Create a delegate instance and put a method in it.
            calc(2, 3, new Sample(Class2.methodMult));
            calc(2, 3, new Sample(Class2.methodPlus));

            //関数ポインタとの違い、
            // 関数ポインタは関数を特定する機能しかもたず
            // インスタンスを特定できないが、Delegateは可能
            Class2 c1 = new Class2();
            Class2 c2 = new Class2();
            Sample s1 = new Sample(c1.method);
            Sample s2 = new Sample(c2.method);
            Console.WriteLine(s1(1, 2).ToString());
            Console.WriteLine(s2(2, 2).ToString());

            //別クラスの異なる名前のメソッドであっても、戻り値と引数だけ合っていれば委譲できる。
            Class2 d1 = new Class2();
            Class3 d2 = new Class3();
            Sample e1 = new Sample(d1.method);
            Sample e2 = new Sample(d2.methodPlus);
            Console.WriteLine(e1(2, 3).ToString());
            Console.WriteLine(e2(3, 4).ToString());
            //オブジェクト情報
            Console.WriteLine(e1.Method.Name);              
            Console.WriteLine(e1.Target.GetType().FullName);


            //継承の実現
            ClassMult f1 = new ClassMult();
            ClassPlus f2 = new ClassPlus();
            calc2(2, 3, f1);
            calc2(2, 3, f2);

            //アクセス権限のない(Private)メソッド呼び出しが、Delegate経由することで可能になる
            Class4 g1 = new Class4();
            Sample2 sample2 = g1.getDelegate();
            sample2("HELLO!");

            //Delegateの合成
            Class5 h1 = new Class5();
            Sample3 sample3_1 = new Sample3(h1.method1);
            sample3_1();
            Sample3 sample3_2 = new Sample3(h1.method2);
            sample3_2();
            //NOTE: Combine 1 and 2
            Sample3 sample3_3 = sample3_1 + sample3_2;
            sample3_3();

            //Delegateリストの変更
            Sample3 ex1 = new Sample3(new Class6("test1").method);
            Sample3 ex2 = new Sample3(new Class6("test2").method);
            Sample3 ex3 = new Sample3(new Class6("test3").method);
            Sample3 ex4 = new Sample3(new Class6("test4").method);
            Console.WriteLine("call 1 method");
            ex1();
            ex1 += ex2;
            ex1 += ex3;
            ex1 += ex4;
            Console.WriteLine("call 4 methods");
            ex1();
            ex1 -= ex2;
            Console.WriteLine("call 3 methods");
            ex1();

            //delegate型同士は戻り値と引数が一致しても同じとは看做されない
            Sample4 sample4 = new Sample4(Class7.method);
            Sample5 sample5 = new Sample5(Class7.method);
            //ERROR:異なるdelegate型のdelegateインスタンスを1つのリストにまとめることはできない。
            //sample4 += sample5;
            sample4();

            Console.ReadLine();
        }
    }
}