まぐらぼ

日々の雑記を書いています。

c#4.0 dynamicの使い方

c#4.0 dynamicの使い方です。この機能は知らなかったです。
Test1 ... dynamic型
Test2 ... Dycnamicクラス
Test3 ... reflectionとの対比

using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    public class Test1
    {
        public class Order
        {
            public int ProductID { get; set; }
            public int Quantity { get; set; }
        }

        // dynamic型
        public static void PMain()
        {
            Order o1 = new Order();
            o1.ProductID = 100;
            o1.Quantity = 1;
            //o1.Description = 0;//コンパイルエラー(メンバがないため)

            object o2 = new Order();
            //o2.ProductID = 100; o2.Quantity = 1;//コンパイルエラー(メンバがないため)

            try
            {
                dynamic o4 = new Order();
                o4.ProductID = 100;         //★ dynamic型なのでコンパイル通過する
                o4.Quantity = 1;

                //! 欠点はtypo検出できない、実行時の負荷大きいなど
                String str = String.Format("{0},{1}", o4.ProductID, o4.Quantity);
                Console.WriteLine("{0}", str);

            }
            catch
            {
                Console.WriteLine("dame");
            }
        }
    }

    // DynamicObjectクラス
    public class Test2 {
        public class Statictics1 { 
            public int TotalAmount { get; set; }
        
            public int TotalQuantity{ get; set;}
            public Statictics1() {
                TotalAmount = 0;
                TotalQuantity = 0;
            }
            public void Add( dynamic order) {
                TotalAmount += (order.Amount ?? 0);
                TotalQuantity += (order.Quantity ?? 0);

            }
        }

        public class Order : DynamicObject 
        {
            private Dictionary<string, object> items = new Dictionary<string, object>();
            
            private const object MyDefault = null;
        
            public override bool TrySetMember(SetMemberBinder binder, object value) 
            {
                string name = binder.Name;
                if (binder.IgnoreCase)
                {
                    name = name.ToLower();
                }
                items[name] = value;
                return true;
            }

            public override bool TryGetMember(GetMemberBinder binder, out object result)
            {
                string name = binder.Name;
                if (binder.IgnoreCase)
                {
                    name = name.ToLower();
                }
                if (!items.TryGetValue(name, out result)) {
                    result = MyDefault;
                }
                return true;
            }
        }

        public static void PMain()
        {
            dynamic o1 = new Order();
            o1.ProductID = 100;//仮想関数が呼ばれる
            o1.Quantity = 1;
       
            dynamic o3 = new Order();
            o3.ProductID = 300;
            o3.Refund = 1000;

            try
            {
                Statictics1 stat = new Statictics1();
                stat.Add(o1);
                stat.Add(o3);

                Console.WriteLine("{0}: {1} ", stat.TotalAmount, stat.TotalQuantity);
            }
            catch
            {
                Console.WriteLine("dame");
            }
        }

    }

    // リクレクションとdynamicの比較
    public class Test3
    {
        
        public class Transport 
        {
            public string Name { get; set; }
            public string How { get; set; }
            public Transport(string n, string h )
            {
                Name = n;
                How = h;
            }
        }
        public class UseReflection {
            public static void PMain() {
                Transport[] transports ={
                    new Transport("001","Land"),
                    new Transport("002","Sea"),
                    new Transport("003","Sea"),
                    new Transport("004","Land"),
                    new Transport("005","Air"),
                };
                var q1 = from t in transports
                         where t.How == "Land"
                         select new { Name = t.Name, Kind = t.How };

                foreach (var t in q1)
                {
                    Print1(t);
                }
                foreach (var t in q1)
                {
                    Print2(t);
                }
            }
            static public void Print1(object o1) 
            {
                Type type = o1.GetType();
                PropertyInfo info1 = type.GetProperty("Name");
                PropertyInfo info2 = type.GetProperty("Kind");
                if (info1 == null || info2 == null)
                {
                    return ;
                }
                object name = info1.GetValue(o1, null) ?? "";
                object kind = info2.GetValue(o1, null) ?? "";
                Console.WriteLine("{0}:{1}",name, kind);

            }

            //★Print1よりも、とても簡単にかけます。
            static public void Print2(dynamic o2 ){
                try{
                    Console.WriteLine("{0} : {1}", o2.Name, o2.Kind);
                }catch(Exception){
                }
            }
        }
    }

    public class Program
    {
        public static void Main(string[] args)
        {
            //  Test1.PMain();
            // Test2.PMain();
            Test3.UseReflection.PMain();
        }
    }
}