• MsgPack MessagePack 测试


    
    using System.Runtime.CompilerServices;
    [assembly: InternalsVisibleTo(MsgPack.CompiledPacker.MethodBuilderPacker.AssemblyName)]
    //========================================================================================================
    //
    // Copyright 2011 Kazuki Oikawa
    //
    // Licensed under the Apache License, Version 2.0 (the "License");
    // you may not use this file except in compliance with the License.
    // You may obtain a copy of the License at
    //
    //   http://www.apache.org/licenses/LICENSE-2.0
    //
    // Unless required by applicable law or agreed to in writing, software
    // distributed under the License is distributed on an "AS IS" BASIS,
    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    // See the License for the specific language governing permissions and
    // limitations under the License.
    //
    //using NUnit.Framework;
    namespace Test
    {
        using System;
        using System.Collections.Generic;
        using System.Linq;
        using Test.Share;
        using MsgPack;
        using Microshaoft;
        //using System.Diagnostics;
        //using Microsoft.VisualStudio.TestTools.UnitTesting;
        //[TestFixture]
        public class Class1
        {
            static void Main(string[] args)
            {
                Class1 c = new Class1();
                int iterations = 1000;
                CodeTimer.ParallelTime
                            (
                                "MsgPack ObjectPacker 并行测试",
                                iterations,
                                () =>
                                {
                                    c.Test_ObjectPacker();
                                }
                            );
                CodeTimer.Time
                            (
                                "MsgPack ObjectPacker 串行测试",
                                iterations,
                                () =>
                                {
                                    c.Test_ObjectPacker();
                                }
                            );
                CodeTimer.ParallelTime
                            (
                                "MsgPack CompiledPacker 并行测试",
                                iterations,
                                () =>
                                {
                                    c.Test_CompiledPacker();
                                }
                            );
                CodeTimer.Time
                            (
                                "MsgPack CompiledPacker 串行测试",
                                iterations,
                                () =>
                                {
                                    c.Test_CompiledPacker();
                                }
                            );
                //CodeTimer.ParallelTime
                //        (
                //            "MsgPack BoxingPacker 并行测试",
                //            iterations,
                //            () =>
                //            {
                //                c.Test_BoxingPacker();
                //            }
                //        );
                //CodeTimer.Time
                //            (
                //                "MsgPack BoxingPacker 串行测试",
                //                iterations,
                //                () =>
                //                {
                //                    c.Test_BoxingPacker();
                //                }
                //            );
                CodeTimer.ParallelTime
                            (
                                "MsgPack ObjectPacker/CompiledPacker 并行测试",
                                iterations,
                                () =>
                                {
                                    c.Test_HybridPacker();
                                }
                            );
                CodeTimer.Time
                            (
                                "MsgPack ObjectPacker/CompiledPacker 串行测试",
                                iterations,
                                () =>
                                {
                                    c.Test_HybridPacker();
                                }
                            );
                Console.WriteLine("Hello World");
                Console.WriteLine(Environment.Version.ToString());
                Console.ReadLine();
            }
            public void Test_HybridPacker()
            {
                ObjectMsgPackHeader header = new ObjectMsgPackHeader();
                header.From = "Microshaoft";
                header.ToList = new string[] { "m1", "m2", "m3" };
                //header.Instance = header;
                ObjectMsgPackBody body = new ObjectMsgPackBody();
                body.Parameter1 = "asdasdas";
                body.Parameter2 = 1000;
                body.ParameterX = new List<string>();
                body.ParameterX.Add("aaaaa");
                body.ParameterX.Add("bbbbb");
                //body.Instance = body;
                byte[] buffer;
                ObjectMsgPack message = new ObjectMsgPack();
                message.Header = new CompiledPacker().Pack(header);
                message.Body = new ObjectPacker().Pack(body);
                message.SenderID = "asdasd";
                message.Signature = new byte[10];
                message.TimeStamp = "2012-03-22";
                buffer = new ObjectPacker().Pack(message);
                //Console.WriteLine("HybridPacker Buffer.Length {0}", buffer.Length);
                ObjectMsgPack x = new ObjectPacker().Unpack<ObjectMsgPack>(buffer);
                ObjectMsgPackHeader y = new CompiledPacker().Unpack<ObjectMsgPackHeader>(x.Header);
                ObjectMsgPackBody z = new ObjectPacker().Unpack<ObjectMsgPackBody>(x.Body);
                Print(x, y, z);
            }
            public void Test_BoxingPacker()
            {
                ObjectMsgPackHeader header = new ObjectMsgPackHeader();
                header.From = "Microshaoft";
                header.ToList = new string[] { "m1", "m2", "m3" };
                //header.Instance = header;
                ObjectMsgPackBody body = new ObjectMsgPackBody();
                body.Parameter1 = "asdasdas";
                body.Parameter2 = 1000;
                body.ParameterX = new List<string>();
                body.ParameterX.Add("aaaaa");
                body.ParameterX.Add("bbbbb");
                //body.Instance = body;
                byte[] buffer;
                ObjectMsgPack message = new ObjectMsgPack();
                message.Header = new BoxingPacker().Pack(header);
                message.Body = new BoxingPacker().Pack(body);
                message.SenderID = "asdasd";
                message.Signature = new byte[10];
                message.TimeStamp = "2012-03-22";
                buffer = new BoxingPacker().Pack(message);
                //Console.WriteLine("BoxingPacker Buffer.Length {0}", buffer.Length);
                ObjectMsgPack x = (ObjectMsgPack) new BoxingPacker().Unpack(buffer);
                ObjectMsgPackHeader y = (ObjectMsgPackHeader) new BoxingPacker().Unpack(x.Header);
                ObjectMsgPackBody z = (ObjectMsgPackBody) new BoxingPacker().Unpack(x.Body);
                Print(x, y, z);
            }
            public void Test_CompiledPacker()
            {
                ObjectMsgPackHeader header = new ObjectMsgPackHeader();
                header.From = "Microshaoft";
                header.ToList = new string[] { "m1", "m2", "m3" };
                //header.Instance = header;
                ObjectMsgPackBody body = new ObjectMsgPackBody();
                body.Parameter1 = "asdasdas";
                body.Parameter2 = 1000;
                body.ParameterX = new List<string>();
                body.ParameterX.Add("aaaaa");
                body.ParameterX.Add("bbbbb");
                //body.Instance = body;
                byte[] buffer;
                ObjectMsgPack message = new ObjectMsgPack();
                message.Header = new CompiledPacker().Pack(header);
                message.Body = new CompiledPacker().Pack(body);
                message.SenderID = "asdasd";
                message.Signature = new byte[10];
                message.TimeStamp = "2012-03-22";
                buffer = new CompiledPacker().Pack(message);
                //Console.WriteLine("CompiledPacker Buffer.Length {0}", buffer.Length);
                ObjectMsgPack x = new CompiledPacker().Unpack<ObjectMsgPack>(buffer);
                ObjectMsgPackHeader y = new CompiledPacker().Unpack<ObjectMsgPackHeader>(x.Header);
                ObjectMsgPackBody z = new CompiledPacker().Unpack<ObjectMsgPackBody>(x.Body);
                Print(x, y, z);
            }
            public void Test_ObjectPacker()
            {
                ObjectMsgPackHeader header = new ObjectMsgPackHeader();
                header.From = "Microshaoft";
                header.ToList = new string[] { "m1", "m2", "m3" };
                //header.Instance = header;
                ObjectMsgPackBody body = new ObjectMsgPackBody();
                body.Parameter1 = "asdasdas";
                body.Parameter2 = 1000;
                body.ParameterX = new List<string>();
                body.ParameterX.Add("aaaaa");
                body.ParameterX.Add("bbbbb");
                //body.Instance = body;
                byte[] buffer;
                ObjectMsgPack message = new ObjectMsgPack();
                message.Header = new ObjectPacker().Pack(header);
                message.Body = new ObjectPacker().Pack(body);
                message.SenderID = "asdasd";
                message.Signature = new byte[10];
                message.TimeStamp = "2012-03-22";
                buffer = new ObjectPacker().Pack(message);
                //Console.WriteLine("ObjectPacker Buffer.Length {0}", buffer.Length);
                ObjectMsgPack x = new ObjectPacker().Unpack<ObjectMsgPack>(buffer);
                ObjectMsgPackHeader y = new ObjectPacker().Unpack<ObjectMsgPackHeader>(x.Header);
                ObjectMsgPackBody z = new ObjectPacker().Unpack<ObjectMsgPackBody>(x.Body);
                Print(x, y, z);
            }
            public void Print(ObjectMsgPack x, ObjectMsgPackHeader y, ObjectMsgPackBody z)
            {
                return;
                Console.WriteLine(x.SenderID);
                Console.WriteLine(x.Signature.Length);
                Console.WriteLine(x.TimeStamp);
                Console.WriteLine(y.From);
                y.ToList.ToList().ForEach
                                    (
                                        s =>
                                        {
                                            Console.WriteLine(s);
                                        }
                                    );
                Console.WriteLine(z.Parameter1);
                Console.WriteLine(z.Parameter12);
                Console.WriteLine(z.FF.F1);
                Console.WriteLine(z.FF.F2);
                z.Parameter3.ToList().ForEach
                            (
                                s =>
                                {
                                    Console.WriteLine(s);
                                }
                            );
            }
        }
    }
    namespace Microshaoft
    {
        using System;
        using System.Diagnostics;
        using System.Threading;
        using System.Threading.Tasks;
        using System.Runtime.InteropServices;
        public static class CodeTimer
        {
            public static void Initialize()
            {
                Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
                Thread.CurrentThread.Priority = ThreadPriority.Highest;
                Time("", 1, () => { });
            }
            public static void ParallelTime(string name, int iteration, Action action)
            {
                if (string.IsNullOrEmpty(name))
                {
                    return;
                }
                // 1.
                ConsoleColor currentForeColor = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.WriteLine(name);
                // 2.
                GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
                int[] gcCounts = new int[GC.MaxGeneration + 1];
                for (int i = 0; i <= GC.MaxGeneration; i++)
                {
                    gcCounts[i] = GC.CollectionCount(i);
                }
                // 3.
                Stopwatch watch = new Stopwatch();
                watch.Start();
                ulong cycleCount = GetCycleCount();
                Parallel.For
                    (
                        0
                        , iteration
                        , i =>
                        {
                            action();
                        }
                    );
                ulong cpuCycles = GetCycleCount() - cycleCount;
                watch.Stop();
                // 4.
                Console.ForegroundColor = currentForeColor;
                Console.WriteLine("\tTime Elapsed:\t" + watch.ElapsedMilliseconds.ToString("N0") + "ms");
                Console.WriteLine("\tCPU Cycles:\t" + cpuCycles.ToString("N0"));
                // 5.
                for (int i = 0; i <= GC.MaxGeneration; i++)
                {
                    int count = GC.CollectionCount(i) - gcCounts[i];
                    Console.WriteLine("\tGen " + i + ": \t\t" + count);
                }
                Console.WriteLine();
            }
            public static void Time(string name, int iteration, Action action)
            {
                if (string.IsNullOrEmpty(name))
                {
                    return;
                }
                // 1.
                ConsoleColor currentForeColor = Console.ForegroundColor;
                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.WriteLine(name);
                // 2.
                GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
                int[] gcCounts = new int[GC.MaxGeneration + 1];
                for (int i = 0; i <= GC.MaxGeneration; i++)
                {
                    gcCounts[i] = GC.CollectionCount(i);
                }
                // 3.
                Stopwatch watch = new Stopwatch();
                watch.Start();
                ulong cycleCount = GetCycleCount();
                for (int i = 0; i < iteration; i++)
                {
                    action();
                }
                ulong cpuCycles = GetCycleCount() - cycleCount;
                watch.Stop();
                // 4.
                Console.ForegroundColor = currentForeColor;
                Console.WriteLine("\tTime Elapsed:\t" + watch.ElapsedMilliseconds.ToString("N0") + "ms");
                Console.WriteLine("\tCPU Cycles:\t" + cpuCycles.ToString("N0"));
                // 5.
                for (int i = 0; i <= GC.MaxGeneration; i++)
                {
                    int count = GC.CollectionCount(i) - gcCounts[i];
                    Console.WriteLine("\tGen " + i + ": \t\t" + count);
                }
                Console.WriteLine();
            }
            private static ulong GetCycleCount()
            {
                ulong cycleCount = 0;
                QueryThreadCycleTime(GetCurrentThread(), ref cycleCount);
                return cycleCount;
            }
            [DllImport("kernel32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
            static extern bool QueryThreadCycleTime(IntPtr threadHandle, ref ulong cycleTime);
            [DllImport("kernel32.dll")]
            static extern IntPtr GetCurrentThread();
        }
    }
    //===============================================================================================================
    namespace Test.Share
    {
        using System;
        using System.Collections.Generic;
        public class ObjectMsgPack
        {
            public string SenderID;
            public string TimeStamp;
            public byte[] Signature;
            public byte[] Header;
            public byte[] Body;
        }
        public class ObjectMsgPackHeader
        {
            //public ObjectMsgPack Container;
            //public ObjectMsgPackHeader Instance;
            public string From;
            public string[] ToList;
        }
        public class ObjectMsgPackBody
        {
            //public ObjectMsgPack Container;
            //public ObjectMsgPackBody Instance;
            public string Parameter1 = "aaaa";
            public int Parameter2 = 100;
            public string Parameter3 = "aaaa";
            public int Parameter4 = 100;
            public string Parameter5 = "aaaa";
            public int Parameter6 = 100;
            public string Parameter7 = "aaaa";
            public int Parameter8 = 100;
            public string Parameter9 = "aaaa";
            public int Parameter10 = 100;
            public string Parameter11 = "aaaa";
            public int Parameter12 = -101;
            public List<string> ParameterX;
            public ComplexType FF = new ComplexType();
        }
        public class ComplexType
        {
            public string F1 = "asdasd";
            public DateTime F2 = DateTime.Parse("2012-03-30 00:00:00.00000");
        }
    }
    //================================================================================================
    namespace MsgPack
    {
        //
        // Copyright 2011 Kazuki Oikawa
        //
        // Licensed under the Apache License, Version 2.0 (the "License");
        // you may not use this file except in compliance with the License.
        // You may obtain a copy of the License at
        //
        //   http://www.apache.org/licenses/LICENSE-2.0
        //
        // Unless required by applicable law or agreed to in writing, software
        // distributed under the License is distributed on an "AS IS" BASIS,
        // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        // See the License for the specific language governing permissions and
        // limitations under the License.
        //
        public enum TypePrefixes : byte
        {
            PositiveFixNum = 0x00, // 0x00 - 0x7f
            NegativeFixNum = 0xe0, // 0xe0 - 0xff
            Nil = 0xc0,
            False = 0xc2,
            True = 0xc3,
            Float = 0xca,
            Double = 0xcb,
            UInt8 = 0xcc,
            UInt16 = 0xcd,
            UInt32 = 0xce,
            UInt64 = 0xcf,
            Int8 = 0xd0,
            Int16 = 0xd1,
            Int32 = 0xd2,
            Int64 = 0xd3,
            Raw16 = 0xda,
            Raw32 = 0xdb,
            Array16 = 0xdc,
            Array32 = 0xdd,
            Map16 = 0xde,
            Map32 = 0xdf,
            FixRaw = 0xa0,        // 0xa0 - 0xbf
            FixArray = 0x90,    // 0x90 - 0x9f
            FixMap = 0x80,        // 0x80 - 0x8f
        }
    }
    namespace MsgPack
    {
        //
        // Copyright 2011 Kazuki Oikawa
        //
        // Licensed under the Apache License, Version 2.0 (the "License");
        // you may not use this file except in compliance with the License.
        // You may obtain a copy of the License at
        //
        //   http://www.apache.org/licenses/LICENSE-2.0
        //
        // Unless required by applicable law or agreed to in writing, software
        // distributed under the License is distributed on an "AS IS" BASIS,
        // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        // See the License for the specific language governing permissions and
        // limitations under the License.
        //
        using System;
        using System.Collections.Generic;
        using System.Reflection;
        public class ReflectionCacheEntry
        {
            const BindingFlags FieldBindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField | BindingFlags.SetField;
            public ReflectionCacheEntry(Type t)
            {
                FieldInfo[] fields = t.GetFields(FieldBindingFlags);
                IDictionary<string, FieldInfo> map = new Dictionary<string, FieldInfo>(fields.Length);
                for (int i = 0; i < fields.Length; i++)
                {
                    FieldInfo f = fields[i];
                    string name = f.Name;
                    int pos;
                    if (name[0] == '<' && (pos = name.IndexOf('>')) > 1)
                    {
                        name = name.Substring(1, pos - 1); // Auto-Property (\<.+\>) <ab>
                    }
                    map[name] = f;
                }
                FieldMap = map;
            }
            public IDictionary<string, FieldInfo> FieldMap { get; private set; }
        }
    }
    namespace MsgPack
    {
        //
        // Copyright 2011 Kazuki Oikawa
        //
        // Licensed under the Apache License, Version 2.0 (the "License");
        // you may not use this file except in compliance with the License.
        // You may obtain a copy of the License at
        //
        //   http://www.apache.org/licenses/LICENSE-2.0
        //
        // Unless required by applicable law or agreed to in writing, software
        // distributed under the License is distributed on an "AS IS" BASIS,
        // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        // See the License for the specific language governing permissions and
        // limitations under the License.
        //
        using System;
        using System.Collections.Generic;
        public static class ReflectionCache
        {
            static Dictionary<Type, ReflectionCacheEntry> _cache;
            static ReflectionCache()
            {
                _cache = new Dictionary<Type, ReflectionCacheEntry>();
            }
            public static ReflectionCacheEntry Lookup(Type type)
            {
                ReflectionCacheEntry entry;
                lock (_cache)
                {
                    if (_cache.TryGetValue(type, out entry))
                    {
                        return entry;
                    }
                }
                entry = new ReflectionCacheEntry(type);
                lock (_cache)
                {
                    _cache[type] = entry;
                }
                return entry;
            }
            public static void RemoveCache(Type type)
            {
                lock (_cache)
                {
                    _cache.Remove(type);
                }
            }
            public static void Clear()
            {
                lock (_cache)
                {
                    _cache.Clear();
                }
            }
        }
    }
    namespace MsgPack
    {
        //
        // Copyright 2011 Kazuki Oikawa
        //
        // Licensed under the Apache License, Version 2.0 (the "License");
        // you may not use this file except in compliance with the License.
        // You may obtain a copy of the License at
        //
        //   http://www.apache.org/licenses/LICENSE-2.0
        //
        // Unless required by applicable law or agreed to in writing, software
        // distributed under the License is distributed on an "AS IS" BASIS,
        // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        // See the License for the specific language governing permissions and
        // limitations under the License.
        //
        using System;
        using System.Collections.Generic;
        using System.IO;
        using System.Reflection;
        using System.Runtime.Serialization;
        using System.Text;
        public class ObjectPacker
        {
            byte[] _buf = new byte[64];
            Encoding _encoding = Encoding.UTF8;
            static Dictionary<Type, PackDelegate> PackerMapping;
            static Dictionary<Type, UnpackDelegate> UnpackerMapping;
            delegate void PackDelegate(ObjectPacker packer, MsgPackWriter writer, object o);
            delegate object UnpackDelegate(ObjectPacker packer, MsgPackReader reader);
            static ObjectPacker()
            {
                PackerMapping = new Dictionary<Type, PackDelegate>();
                UnpackerMapping = new Dictionary<Type, UnpackDelegate>();
                PackerMapping.Add(typeof(string), StringPacker);
                UnpackerMapping.Add(typeof(string), StringUnpacker);
            }
            public byte[] Pack(object o)
            {
                using (MemoryStream ms = new MemoryStream())
                {
                    Pack(ms, o);
                    return ms.ToArray();
                }
            }
            public void Pack(Stream strm, object o)
            {
                if (o != null && o.GetType().IsPrimitive)
                    throw new NotSupportedException();
                MsgPackWriter writer = new MsgPackWriter(strm);
                Pack(writer, o);
            }
            void Pack(MsgPackWriter writer, object o)
            {
                if (o == null)
                {
                    writer.WriteNil();
                    return;
                }
                Type t = o.GetType();
                if (t.IsPrimitive)
                {
                    if (t.Equals(typeof(int)))
                    {
                        writer.Write((int)o);
                    }
                    else if (t.Equals(typeof(uint)))
                    {
                        writer.Write((uint)o);
                    }
                    else if (t.Equals(typeof(float)))
                    {
                        writer.Write((float)o);
                    }
                    else if (t.Equals(typeof(double)))
                    {
                        writer.Write((double)o);
                    }
                    else if (t.Equals(typeof(long)))
                    {
                        writer.Write((long)o);
                    }
                    else if (t.Equals(typeof(ulong)))
                    {
                        writer.Write((ulong)o);
                    }
                    else if (t.Equals(typeof(bool)))
                    {
                        writer.Write((bool)o);
                    }
                    else if (t.Equals(typeof(byte)))
                    {
                        writer.Write((byte)o);
                    }
                    else if (t.Equals(typeof(sbyte)))
                    {
                        writer.Write((sbyte)o);
                    }
                    else if (t.Equals(typeof(short)))
                    {
                        writer.Write((short)o);
                    }
                    else if (t.Equals(typeof(ushort)))
                    {
                        writer.Write((ushort)o);
                    }
                    else if (t.Equals(typeof(char)))
                    {
                        writer.Write((ushort)(char)o);
                    }
                    else
                    {
                        throw new NotSupportedException();
                    }
                    return;
                }
                PackDelegate packer;
                if (PackerMapping.TryGetValue(t, out packer))
                {
                    packer(this, writer, o);
                    return;
                }
                if (t.IsArray)
                {
                    Array ary = (Array)o;
                    writer.WriteArrayHeader(ary.Length);
                    for (int i = 0; i < ary.Length; i++)
                        Pack(writer, ary.GetValue(i));
                    return;
                }
                ReflectionCacheEntry entry = ReflectionCache.Lookup(t);
                writer.WriteMapHeader(entry.FieldMap.Count);
                foreach (KeyValuePair<string, FieldInfo> pair in entry.FieldMap)
                {
                    writer.Write(pair.Key, _buf);
                    object v = pair.Value.GetValue(o);
                    if (pair.Value.FieldType.IsInterface && v != null)
                    {
                        writer.WriteArrayHeader(2);
                        writer.Write(v.GetType().FullName);
                    }
                    Pack(writer, v);
                }
            }
            public T Unpack<T>(byte[] buf)
            {
                return Unpack<T>(buf, 0, buf.Length);
            }
            public T Unpack<T>(byte[] buf, int offset, int size)
            {
                using (MemoryStream ms = new MemoryStream(buf, offset, size))
                {
                    return Unpack<T>(ms);
                }
            }
            public T Unpack<T>(Stream strm)
            {
                if (typeof(T).IsPrimitive)
                    throw new NotSupportedException();
                MsgPackReader reader = new MsgPackReader(strm);
                return (T)Unpack(reader, typeof(T));
            }
            public object Unpack(Type type, byte[] buf)
            {
                return Unpack(type, buf, 0, buf.Length);
            }
            public object Unpack(Type type, byte[] buf, int offset, int size)
            {
                using (MemoryStream ms = new MemoryStream(buf, offset, size))
                {
                    return Unpack(type, ms);
                }
            }
            public object Unpack(Type type, Stream strm)
            {
                if (type.IsPrimitive)
                    throw new NotSupportedException();
                MsgPackReader reader = new MsgPackReader(strm);
                return Unpack(reader, type);
            }
            object Unpack(MsgPackReader reader, Type t)
            {
                if (t.IsPrimitive)
                {
                    if (!reader.Read()) throw new FormatException();
                    if (t.Equals(typeof(int)) && reader.IsSigned()) return reader.ValueSigned;
                    else if (t.Equals(typeof(uint)) && reader.IsUnsigned()) return reader.ValueUnsigned;
                    else if (t.Equals(typeof(float)) && reader.Type == TypePrefixes.Float) return reader.ValueFloat;
                    else if (t.Equals(typeof(double)) && reader.Type == TypePrefixes.Double) return reader.ValueDouble;
                    else if (t.Equals(typeof(long)))
                    {
                        if (reader.IsSigned64())
                            return reader.ValueSigned64;
                        if (reader.IsSigned())
                            return (long)reader.ValueSigned;
                    }
                    else if (t.Equals(typeof(ulong)))
                    {
                        if (reader.IsUnsigned64())
                            return reader.ValueUnsigned64;
                        if (reader.IsUnsigned())
                            return (ulong)reader.ValueUnsigned;
                    }
                    else if (t.Equals(typeof(bool)) && reader.IsBoolean()) return (reader.Type == TypePrefixes.True);
                    else if (t.Equals(typeof(byte)) && reader.IsUnsigned()) return (byte)reader.ValueUnsigned;
                    else if (t.Equals(typeof(sbyte)) && reader.IsSigned()) return (sbyte)reader.ValueSigned;
                    else if (t.Equals(typeof(short)) && reader.IsSigned()) return (short)reader.ValueSigned;
                    else if (t.Equals(typeof(ushort)) && reader.IsUnsigned()) return (ushort)reader.ValueUnsigned;
                    else if (t.Equals(typeof(char)) && reader.IsUnsigned()) return (char)reader.ValueUnsigned;
                    else throw new NotSupportedException();
                }
                UnpackDelegate unpacker;
                if (UnpackerMapping.TryGetValue(t, out unpacker))
                    return unpacker(this, reader);
                if (t.IsArray)
                {
                    if (!reader.Read() || (!reader.IsArray() && reader.Type != TypePrefixes.Nil))
                        throw new FormatException();
                    if (reader.Type == TypePrefixes.Nil)
                        return null;
                    Type et = t.GetElementType();
                    Array ary = Array.CreateInstance(et, (int)reader.Length);
                    for (int i = 0; i < ary.Length; i++)
                        ary.SetValue(Unpack(reader, et), i);
                    return ary;
                }
                if (!reader.Read())
                    throw new FormatException();
                if (reader.Type == TypePrefixes.Nil)
                    return null;
                if (t.IsInterface)
                {
                    if (reader.Type != TypePrefixes.FixArray && reader.Length != 2)
                        throw new FormatException();
                    if (!reader.Read() || !reader.IsRaw())
                        throw new FormatException();
                    CheckBufferSize((int)reader.Length);
                    reader.ReadValueRaw(_buf, 0, (int)reader.Length);
                    t = Type.GetType(Encoding.UTF8.GetString(_buf, 0, (int)reader.Length));
                    if (!reader.Read() || reader.Type == TypePrefixes.Nil)
                        throw new FormatException();
                }
                if (!reader.IsMap())
                    throw new FormatException();
                object o = FormatterServices.GetUninitializedObject(t);
                ReflectionCacheEntry entry = ReflectionCache.Lookup(t);
                int members = (int)reader.Length;
                for (int i = 0; i < members; i++)
                {
                    if (!reader.Read() || !reader.IsRaw())
                        throw new FormatException();
                    CheckBufferSize((int)reader.Length);
                    reader.ReadValueRaw(_buf, 0, (int)reader.Length);
                    string name = Encoding.UTF8.GetString(_buf, 0, (int)reader.Length);
                    FieldInfo f;
                    if (!entry.FieldMap.TryGetValue(name, out f))
                        throw new FormatException();
                    f.SetValue(o, Unpack(reader, f.FieldType));
                }
                IDeserializationCallback callback = o as IDeserializationCallback;
                if (callback != null)
                    callback.OnDeserialization(this);
                return o;
            }
            void CheckBufferSize(int size)
            {
                if (_buf.Length < size)
                    Array.Resize<byte>(ref _buf, size);
            }
            static void StringPacker(ObjectPacker packer, MsgPackWriter writer, object o)
            {
                writer.Write(Encoding.UTF8.GetBytes((string)o));
            }
            static object StringUnpacker(ObjectPacker packer, MsgPackReader reader)
            {
                if (!reader.Read())
                    throw new FormatException();
                if (reader.Type == TypePrefixes.Nil)
                    return null;
                if (!reader.IsRaw())
                    throw new FormatException();
                packer.CheckBufferSize((int)reader.Length);
                reader.ReadValueRaw(packer._buf, 0, (int)reader.Length);
                return Encoding.UTF8.GetString(packer._buf, 0, (int)reader.Length);
            }
        }
    }
    namespace MsgPack
    {
        //
        // Copyright 2011 Kazuki Oikawa
        //
        // Licensed under the Apache License, Version 2.0 (the "License");
        // you may not use this file except in compliance with the License.
        // You may obtain a copy of the License at
        //
        //   http://www.apache.org/licenses/LICENSE-2.0
        //
        // Unless required by applicable law or agreed to in writing, software
        // distributed under the License is distributed on an "AS IS" BASIS,
        // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        // See the License for the specific language governing permissions and
        // limitations under the License.
        //
        using System;
        using System.IO;
        using System.Text;
        public class MsgPackWriter
        {
            Stream _strm;
            Encoding _encoding = Encoding.UTF8;
            Encoder _encoder = Encoding.UTF8.GetEncoder();
            byte[] _tmp = new byte[9];
            byte[] _buf = new byte[64];
            public MsgPackWriter(Stream strm)
            {
                _strm = strm;
            }
            public void Write(byte x)
            {
                if (x < 128)
                {
                    _strm.WriteByte(x);
                }
                else
                {
                    byte[] tmp = _tmp;
                    tmp[0] = 0xcc;
                    tmp[1] = x;
                    _strm.Write(tmp, 0, 2);
                }
            }
            public void Write(ushort x)
            {
                if (x < 0x100)
                {
                    Write((byte)x);
                }
                else
                {
                    byte[] tmp = _tmp;
                    tmp[0] = 0xcd;
                    tmp[1] = (byte)(x >> 8);
                    tmp[2] = (byte)x;
                    _strm.Write(tmp, 0, 3);
                }
            }
            public void Write(char x)
            {
                Write((ushort)x);
            }
            public void Write(uint x)
            {
                if (x < 0x10000)
                {
                    Write((ushort)x);
                }
                else
                {
                    byte[] tmp = _tmp;
                    tmp[0] = 0xce;
                    tmp[1] = (byte)(x >> 24);
                    tmp[2] = (byte)(x >> 16);
                    tmp[3] = (byte)(x >> 8);
                    tmp[4] = (byte)x;
                    _strm.Write(tmp, 0, 5);
                }
            }
            public void Write(ulong x)
            {
                if (x < 0x100000000)
                {
                    Write((uint)x);
                }
                else
                {
                    byte[] tmp = _tmp;
                    tmp[0] = 0xcf;
                    tmp[1] = (byte)(x >> 56);
                    tmp[2] = (byte)(x >> 48);
                    tmp[3] = (byte)(x >> 40);
                    tmp[4] = (byte)(x >> 32);
                    tmp[5] = (byte)(x >> 24);
                    tmp[6] = (byte)(x >> 16);
                    tmp[7] = (byte)(x >> 8);
                    tmp[8] = (byte)x;
                    _strm.Write(tmp, 0, 9);
                }
            }
            public void Write(sbyte x)
            {
                if (x >= -32 && x <= -1)
                {
                    _strm.WriteByte((byte)(0xe0 | (byte)x));
                }
                else if (x >= 0 && x <= 127)
                {
                    _strm.WriteByte((byte)x);
                }
                else
                {
                    byte[] tmp = _tmp;
                    tmp[0] = 0xd0;
                    tmp[1] = (byte)x;
                    _strm.Write(tmp, 0, 2);
                }
            }
            public void Write(short x)
            {
                if (x >= sbyte.MinValue && x <= sbyte.MaxValue)
                {
                    Write((sbyte)x);
                }
                else
                {
                    byte[] tmp = _tmp;
                    tmp[0] = 0xd1;
                    tmp[1] = (byte)(x >> 8);
                    tmp[2] = (byte)x;
                    _strm.Write(tmp, 0, 3);
                }
            }
            public void Write(int x)
            {
                if (x >= short.MinValue && x <= short.MaxValue)
                {
                    Write((short)x);
                }
                else
                {
                    byte[] tmp = _tmp;
                    tmp[0] = 0xd2;
                    tmp[1] = (byte)(x >> 24);
                    tmp[2] = (byte)(x >> 16);
                    tmp[3] = (byte)(x >> 8);
                    tmp[4] = (byte)x;
                    _strm.Write(tmp, 0, 5);
                }
            }
            public void Write(long x)
            {
                if (x >= int.MinValue && x <= int.MaxValue)
                {
                    Write((int)x);
                }
                else
                {
                    byte[] tmp = _tmp;
                    tmp[0] = 0xd3;
                    tmp[1] = (byte)(x >> 56);
                    tmp[2] = (byte)(x >> 48);
                    tmp[3] = (byte)(x >> 40);
                    tmp[4] = (byte)(x >> 32);
                    tmp[5] = (byte)(x >> 24);
                    tmp[6] = (byte)(x >> 16);
                    tmp[7] = (byte)(x >> 8);
                    tmp[8] = (byte)x;
                    _strm.Write(tmp, 0, 9);
                }
            }
            public void WriteNil()
            {
                _strm.WriteByte(0xc0);
            }
            public void Write(bool x)
            {
                _strm.WriteByte((byte)(x ? 0xc3 : 0xc2));
            }
            public void Write(float x)
            {
                byte[] raw = BitConverter.GetBytes(x); // unsafeコードを使う?
                byte[] tmp = _tmp;
                tmp[0] = 0xca;
                if (BitConverter.IsLittleEndian)
                {
                    tmp[1] = raw[3];
                    tmp[2] = raw[2];
                    tmp[3] = raw[1];
                    tmp[4] = raw[0];
                }
                else
                {
                    tmp[1] = raw[0];
                    tmp[2] = raw[1];
                    tmp[3] = raw[2];
                    tmp[4] = raw[3];
                }
                _strm.Write(tmp, 0, 5);
            }
            public void Write(double x)
            {
                byte[] raw = BitConverter.GetBytes(x); // unsafeコードを使う?
                byte[] tmp = _tmp;
                tmp[0] = 0xcb;
                if (BitConverter.IsLittleEndian)
                {
                    tmp[1] = raw[7];
                    tmp[2] = raw[6];
                    tmp[3] = raw[5];
                    tmp[4] = raw[4];
                    tmp[5] = raw[3];
                    tmp[6] = raw[2];
                    tmp[7] = raw[1];
                    tmp[8] = raw[0];
                }
                else
                {
                    tmp[1] = raw[0];
                    tmp[2] = raw[1];
                    tmp[3] = raw[2];
                    tmp[4] = raw[3];
                    tmp[5] = raw[4];
                    tmp[6] = raw[5];
                    tmp[7] = raw[6];
                    tmp[8] = raw[7];
                }
                _strm.Write(tmp, 0, 9);
            }
            public void Write(byte[] bytes)
            {
                WriteRawHeader(bytes.Length);
                _strm.Write(bytes, 0, bytes.Length);
            }
            public void WriteRawHeader(int N)
            {
                WriteLengthHeader(N, 32, 0xa0, 0xda, 0xdb);
            }
            public void WriteArrayHeader(int N)
            {
                WriteLengthHeader(N, 16, 0x90, 0xdc, 0xdd);
            }
            public void WriteMapHeader(int N)
            {
                WriteLengthHeader(N, 16, 0x80, 0xde, 0xdf);
            }
            void WriteLengthHeader(int N, int fix_length, byte fix_prefix, byte len16bit_prefix, byte len32bit_prefix)
            {
                if (N < fix_length)
                {
                    _strm.WriteByte((byte)(fix_prefix | N));
                }
                else
                {
                    byte[] tmp = _tmp;
                    int header_len;
                    if (N < 0x10000)
                    {
                        tmp[0] = len16bit_prefix;
                        tmp[1] = (byte)(N >> 8);
                        tmp[2] = (byte)N;
                        header_len = 3;
                    }
                    else
                    {
                        tmp[0] = len32bit_prefix;
                        tmp[1] = (byte)(N >> 24);
                        tmp[2] = (byte)(N >> 16);
                        tmp[3] = (byte)(N >> 8);
                        tmp[4] = (byte)N;
                        header_len = 5;
                    }
                    _strm.Write(tmp, 0, header_len);
                }
            }
            public void Write(string x)
            {
                Write(x, false);
            }
            public void Write(string x, bool highProbAscii)
            {
                Write(x, _buf, highProbAscii);
            }
            public void Write(string x, byte[] buf)
            {
                Write(x, buf, false);
            }
            public unsafe void Write(string x, byte[] buf, bool highProbAscii)
            {
                Encoder encoder = _encoder;
                fixed (char* pstr = x)
                fixed (byte* pbuf = buf)
                {
                    if (highProbAscii && x.Length <= buf.Length)
                    {
                        bool isAsciiFullCompatible = true;
                        for (int i = 0; i < x.Length; i++)
                        {
                            int v = (int)pstr[i];
                            if (v > 0x7f)
                            {
                                isAsciiFullCompatible = false;
                                break;
                            }
                            buf[i] = (byte)v;
                        }
                        if (isAsciiFullCompatible)
                        {
                            WriteRawHeader(x.Length);
                            _strm.Write(buf, 0, x.Length);
                            return;
                        }
                    }
                    WriteRawHeader(encoder.GetByteCount(pstr, x.Length, true));
                    int str_len = x.Length;
                    char* p = pstr;
                    int convertedChars, bytesUsed;
                    bool completed = true;
                    while (str_len > 0 || !completed)
                    {
                        encoder.Convert(p, str_len, pbuf, buf.Length, false, out convertedChars, out bytesUsed, out completed);
                        _strm.Write(buf, 0, bytesUsed);
                        str_len -= convertedChars;
                        p += convertedChars;
                    }
                }
            }
        }
    }
    namespace MsgPack
    {
        //
        // Copyright 2011 Kazuki Oikawa
        //
        // Licensed under the Apache License, Version 2.0 (the "License");
        // you may not use this file except in compliance with the License.
        // You may obtain a copy of the License at
        //
        //   http://www.apache.org/licenses/LICENSE-2.0
        //
        // Unless required by applicable law or agreed to in writing, software
        // distributed under the License is distributed on an "AS IS" BASIS,
        // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        // See the License for the specific language governing permissions and
        // limitations under the License.
        //
        using System;
        using System.IO;
        using System.Text;
        public class MsgPackReader
        {
            Stream _strm;
            byte[] _tmp0 = new byte[8];
            byte[] _tmp1 = new byte[8];
            Encoding _encoding = Encoding.UTF8;
            Decoder _decoder = Encoding.UTF8.GetDecoder();
            byte[] _buf = new byte[64];
            public MsgPackReader(Stream strm)
            {
                _strm = strm;
            }
            public TypePrefixes Type { get; private set; }
            public bool ValueBoolean { get; private set; }
            public uint Length { get; private set; }
            public uint ValueUnsigned { get; private set; }
            public ulong ValueUnsigned64 { get; private set; }
            public int ValueSigned { get; private set; }
            public long ValueSigned64 { get; private set; }
            public float ValueFloat { get; private set; }
            public double ValueDouble { get; private set; }
            public bool IsSigned()
            {
                return this.Type == TypePrefixes.NegativeFixNum ||
                    this.Type == TypePrefixes.PositiveFixNum ||
                    this.Type == TypePrefixes.Int8 ||
                    this.Type == TypePrefixes.Int16 ||
                    this.Type == TypePrefixes.Int32;
            }
            public bool IsBoolean()
            {
                return this.Type == TypePrefixes.True || this.Type == TypePrefixes.False;
            }
            public bool IsSigned64()
            {
                return this.Type == TypePrefixes.Int64;
            }
            public bool IsUnsigned()
            {
                return this.Type == TypePrefixes.PositiveFixNum ||
                    this.Type == TypePrefixes.UInt8 ||
                    this.Type == TypePrefixes.UInt16 ||
                    this.Type == TypePrefixes.UInt32;
            }
            public bool IsUnsigned64()
            {
                return this.Type == TypePrefixes.UInt64;
            }
            public bool IsRaw()
            {
                return this.Type == TypePrefixes.FixRaw || this.Type == TypePrefixes.Raw16 || this.Type == TypePrefixes.Raw32;
            }
            public bool IsArray()
            {
                return this.Type == TypePrefixes.FixArray || this.Type == TypePrefixes.Array16 || this.Type == TypePrefixes.Array32;
            }
            public bool IsMap()
            {
                return this.Type == TypePrefixes.FixMap || this.Type == TypePrefixes.Map16 || this.Type == TypePrefixes.Map32;
            }
            public bool Read()
            {
                byte[] tmp0 = _tmp0, tmp1 = _tmp1;
                int x = _strm.ReadByte();
                if (x < 0)
                    return false; // EOS
                if (x >= 0x00 && x <= 0x7f)
                {
                    this.Type = TypePrefixes.PositiveFixNum;
                }
                else if (x >= 0xe0 && x <= 0xff)
                {
                    this.Type = TypePrefixes.NegativeFixNum;
                }
                else if (x >= 0xa0 && x <= 0xbf)
                {
                    this.Type = TypePrefixes.FixRaw;
                }
                else if (x >= 0x90 && x <= 0x9f)
                {
                    this.Type = TypePrefixes.FixArray;
                }
                else if (x >= 0x80 && x <= 0x8f)
                {
                    this.Type = TypePrefixes.FixMap;
                }
                else
                {
                    this.Type = (TypePrefixes)x;
                }
                switch (this.Type)
                {
                    case TypePrefixes.Nil:
                        break;
                    case TypePrefixes.False:
                        ValueBoolean = false;
                        break;
                    case TypePrefixes.True:
                        ValueBoolean = true;
                        break;
                    case TypePrefixes.Float:
                        _strm.Read(tmp0, 0, 4);
                        if (BitConverter.IsLittleEndian)
                        {
                            tmp1[0] = tmp0[3];
                            tmp1[1] = tmp0[2];
                            tmp1[2] = tmp0[1];
                            tmp1[3] = tmp0[0];
                            ValueFloat = BitConverter.ToSingle(tmp1, 0);
                        }
                        else
                        {
                            ValueFloat = BitConverter.ToSingle(tmp0, 0);
                        }
                        break;
                    case TypePrefixes.Double:
                        _strm.Read(tmp0, 0, 8);
                        if (BitConverter.IsLittleEndian)
                        {
                            tmp1[0] = tmp0[7];
                            tmp1[1] = tmp0[6];
                            tmp1[2] = tmp0[5];
                            tmp1[3] = tmp0[4];
                            tmp1[4] = tmp0[3];
                            tmp1[5] = tmp0[2];
                            tmp1[6] = tmp0[1];
                            tmp1[7] = tmp0[0];
                            ValueDouble = BitConverter.ToDouble(tmp1, 0);
                        }
                        else
                        {
                            ValueDouble = BitConverter.ToDouble(tmp0, 0);
                        }
                        break;
                    case TypePrefixes.NegativeFixNum:
                        ValueSigned = (x & 0x1f) - 0x20;
                        break;
                    case TypePrefixes.PositiveFixNum:
                        ValueSigned = x & 0x7f;
                        ValueUnsigned = (uint)ValueSigned;
                        break;
                    case TypePrefixes.UInt8:
                        x = _strm.ReadByte();
                        if (x < 0)
                            throw new FormatException();
                        ValueUnsigned = (uint)x;
                        break;
                    case TypePrefixes.UInt16:
                        if (_strm.Read(tmp0, 0, 2) != 2)
                            throw new FormatException();
                        ValueUnsigned = ((uint)tmp0[0] << 8) | (uint)tmp0[1];
                        break;
                    case TypePrefixes.UInt32:
                        if (_strm.Read(tmp0, 0, 4) != 4)
                            throw new FormatException();
                        ValueUnsigned = ((uint)tmp0[0] << 24) | ((uint)tmp0[1] << 16) | ((uint)tmp0[2] << 8) | (uint)tmp0[3];
                        break;
                    case TypePrefixes.UInt64:
                        if (_strm.Read(tmp0, 0, 8) != 8)
                            throw new FormatException();
                        ValueUnsigned64 = ((ulong)tmp0[0] << 56) | ((ulong)tmp0[1] << 48) | ((ulong)tmp0[2] << 40) | ((ulong)tmp0[3] << 32) | ((ulong)tmp0[4] << 24) | ((ulong)tmp0[5] << 16) | ((ulong)tmp0[6] << 8) | (ulong)tmp0[7];
                        break;
                    case TypePrefixes.Int8:
                        x = _strm.ReadByte();
                        if (x < 0)
                            throw new FormatException();
                        ValueSigned = (sbyte)x;
                        break;
                    case TypePrefixes.Int16:
                        if (_strm.Read(tmp0, 0, 2) != 2)
                            throw new FormatException();
                        ValueSigned = (short)((tmp0[0] << 8) | tmp0[1]);
                        break;
                    case TypePrefixes.Int32:
                        if (_strm.Read(tmp0, 0, 4) != 4)
                            throw new FormatException();
                        ValueSigned = (tmp0[0] << 24) | (tmp0[1] << 16) | (tmp0[2] << 8) | tmp0[3];
                        break;
                    case TypePrefixes.Int64:
                        if (_strm.Read(tmp0, 0, 8) != 8)
                            throw new FormatException();
                        ValueSigned64 = ((long)tmp0[0] << 56) | ((long)tmp0[1] << 48) | ((long)tmp0[2] << 40) | ((long)tmp0[3] << 32) | ((long)tmp0[4] << 24) | ((long)tmp0[5] << 16) | ((long)tmp0[6] << 8) | (long)tmp0[7];
                        break;
                    case TypePrefixes.FixRaw:
                        Length = (uint)(x & 0x1f);
                        break;
                    case TypePrefixes.FixArray:
                    case TypePrefixes.FixMap:
                        Length = (uint)(x & 0xf);
                        break;
                    case TypePrefixes.Raw16:
                    case TypePrefixes.Array16:
                    case TypePrefixes.Map16:
                        if (_strm.Read(tmp0, 0, 2) != 2)
                            throw new FormatException();
                        Length = ((uint)tmp0[0] << 8) | (uint)tmp0[1];
                        break;
                    case TypePrefixes.Raw32:
                    case TypePrefixes.Array32:
                    case TypePrefixes.Map32:
                        if (_strm.Read(tmp0, 0, 4) != 4)
                            throw new FormatException();
                        Length = ((uint)tmp0[0] << 24) | ((uint)tmp0[1] << 16) | ((uint)tmp0[2] << 8) | (uint)tmp0[3];
                        break;
                    default:
                        throw new FormatException();
                }
                return true;
            }
            public int ReadValueRaw(byte[] buf, int offset, int count)
            {
                return _strm.Read(buf, offset, count);
            }
            public string ReadRawString()
            {
                return ReadRawString(_buf);
            }
            public unsafe string ReadRawString(byte[] buf)
            {
                if (this.Length < buf.Length)
                {
                    if (ReadValueRaw(buf, 0, (int)this.Length) != this.Length)
                    {
                        throw new FormatException();
                    }
                    return _encoding.GetString(buf, 0, (int)this.Length);
                }
                // Poor implementation
                byte[] tmp = new byte[(int)this.Length];
                if (ReadValueRaw(tmp, 0, tmp.Length) != tmp.Length)
                    throw new FormatException();
                return _encoding.GetString(tmp);
            }
        }
    }
    namespace MsgPack
    {
        //
        // Copyright 2011 Kazuki Oikawa
        //
        // Licensed under the Apache License, Version 2.0 (the "License");
        // you may not use this file except in compliance with the License.
        // You may obtain a copy of the License at
        //
        //   http://www.apache.org/licenses/LICENSE-2.0
        //
        // Unless required by applicable law or agreed to in writing, software
        // distributed under the License is distributed on an "AS IS" BASIS,
        // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        // See the License for the specific language governing permissions and
        // limitations under the License.
        //
        using System;
        using System.Collections.Generic;
        using System.IO;
        using System.Reflection;
        using System.Reflection.Emit;
        using System.Threading;
        using MsgPack.Compiler;
        public class CompiledPacker
        {
            static PackerBase _publicFieldPacker, _allFieldPacker;
            PackerBase _packer;
            static CompiledPacker()
            {
                _publicFieldPacker = new MethodBuilderPacker();
                _allFieldPacker = new DynamicMethodPacker();
            }
            public CompiledPacker() : this(false) { }
            public CompiledPacker(bool packPrivateField)
            {
                _packer = (packPrivateField ? _allFieldPacker : _publicFieldPacker);
            }
            public void Prepare<T>()
            {
                _packer.CreatePacker<T>();
                _packer.CreateUnpacker<T>();
            }
            #region Generics Pack/Unpack Methods
            public byte[] Pack<T>(T o)
            {
                using (MemoryStream ms = new MemoryStream())
                {
                    Pack<T>(ms, o);
                    return ms.ToArray();
                }
            }
            public void Pack<T>(Stream strm, T o)
            {
                _packer.CreatePacker<T>()(new MsgPackWriter(strm), o);
            }
            public T Unpack<T>(byte[] buf)
            {
                return Unpack<T>(buf, 0, buf.Length);
            }
            public T Unpack<T>(byte[] buf, int offset, int size)
            {
                using (MemoryStream ms = new MemoryStream(buf, offset, size))
                {
                    return Unpack<T>(ms);
                }
            }
            public T Unpack<T>(Stream strm)
            {
                return _packer.CreateUnpacker<T>()(new MsgPackReader(strm));
            }
            #endregion
            #region Non-generics Pack/Unpack Methods
            public byte[] Pack(object o)
            {
                using (MemoryStream ms = new MemoryStream())
                {
                    Pack(ms, o);
                    return ms.ToArray();
                }
            }
            public void Pack(Stream strm, object o)
            {
                throw new NotImplementedException();
            }
            public object Unpack(Type t, byte[] buf)
            {
                return Unpack(t, buf, 0, buf.Length);
            }
            public object Unpack(Type t, byte[] buf, int offset, int size)
            {
                using (MemoryStream ms = new MemoryStream(buf, offset, size))
                {
                    return Unpack(t, ms);
                }
            }
            public object Unpack(Type t, Stream strm)
            {
                throw new NotImplementedException();
            }
            #endregion
            #region Compiled Packer Implementations
            public abstract class PackerBase
            {
                Dictionary<Type, Delegate> _packers = new Dictionary<Type, Delegate>();
                Dictionary<Type, Delegate> _unpackers = new Dictionary<Type, Delegate>();
                protected Dictionary<Type, MethodInfo> _packMethods = new Dictionary<Type, MethodInfo>();
                protected Dictionary<Type, MethodInfo> _unpackMethods = new Dictionary<Type, MethodInfo>();
                protected PackerBase()
                {
                    DefaultPackMethods.Register(_packMethods, _unpackMethods);
                }
                public Action<MsgPackWriter, T> CreatePacker<T>()
                {
                    Delegate d;
                    lock (_packers)
                    {
                        if (!_packers.TryGetValue(typeof(T), out d))
                        {
                            d = CreatePacker_Internal<T>();
                            _packers.Add(typeof(T), d);
                        }
                    }
                    return (Action<MsgPackWriter, T>)d;
                }
                public Func<MsgPackReader, T> CreateUnpacker<T>()
                {
                    Delegate d;
                    lock (_unpackers)
                    {
                        if (!_unpackers.TryGetValue(typeof(T), out d))
                        {
                            d = CreateUnpacker_Internal<T>();
                            _unpackers.Add(typeof(T), d);
                        }
                    }
                    return (Func<MsgPackReader, T>)d;
                }
                protected abstract Action<MsgPackWriter, T> CreatePacker_Internal<T>();
                protected abstract Func<MsgPackReader, T> CreateUnpacker_Internal<T>();
            }
            public sealed class DynamicMethodPacker : PackerBase
            {
                private static MethodInfo LookupMemberMappingMethod;
                static Dictionary<Type, IDictionary<string, int>> UnpackMemberMappings;
                static DynamicMethodPacker()
                {
                    UnpackMemberMappings = new Dictionary<Type, IDictionary<string, int>>();
                    LookupMemberMappingMethod = typeof(DynamicMethodPacker).GetMethod("LookupMemberMapping", BindingFlags.Static | BindingFlags.NonPublic);
                }
                public DynamicMethodPacker()
                    : base()
                {
                }
                protected override Action<MsgPackWriter, T> CreatePacker_Internal<T>()
                {
                    DynamicMethod dm = CreatePacker(typeof(T), CreatePackDynamicMethod(typeof(T)));
                    return (Action<MsgPackWriter, T>)dm.CreateDelegate(typeof(Action<MsgPackWriter, T>));
                }
                protected override Func<MsgPackReader, T> CreateUnpacker_Internal<T>()
                {
                    DynamicMethod dm = CreateUnpacker(typeof(T), CreateUnpackDynamicMethod(typeof(T)));
                    return (Func<MsgPackReader, T>)dm.CreateDelegate(typeof(Func<MsgPackReader, T>));
                }
                DynamicMethod CreatePacker(Type t, DynamicMethod dm)
                {
                    ILGenerator il = dm.GetILGenerator();
                    _packMethods.Add(t, dm);
                    PackILGenerator.EmitPackCode(t, dm, il, LookupMembers, FormatMemberName, LookupPackMethod);
                    return dm;
                }
                DynamicMethod CreateUnpacker(Type t, DynamicMethod dm)
                {
                    ILGenerator il = dm.GetILGenerator();
                    _unpackMethods.Add(t, dm);
                    PackILGenerator.EmitUnpackCode(t, dm, il, LookupMembers, FormatMemberName, LookupUnpackMethod,
                        LookupMemberMapping, LookupMemberMappingMethod);
                    return dm;
                }
                static DynamicMethod CreatePackDynamicMethod(Type t)
                {
                    return CreateDynamicMethod(typeof(void), new Type[] { typeof(MsgPackWriter), t });
                }
                static DynamicMethod CreateUnpackDynamicMethod(Type t)
                {
                    return CreateDynamicMethod(t, new Type[] { typeof(MsgPackReader) });
                }
                static MemberInfo[] LookupMembers(Type t)
                {
                    BindingFlags baseFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
                    List<MemberInfo> list = new List<MemberInfo>();
                    list.AddRange(t.GetFields(baseFlags));
                    // TODO: Add NonSerialized Attribute Filter ?
                    return list.ToArray();
                }
                MethodInfo LookupPackMethod(Type t)
                {
                    MethodInfo mi;
                    DynamicMethod dm;
                    if (_packMethods.TryGetValue(t, out mi))
                        return mi;
                    dm = CreatePackDynamicMethod(t);
                    return CreatePacker(t, dm);
                }
                MethodInfo LookupUnpackMethod(Type t)
                {
                    MethodInfo mi;
                    if (_unpackMethods.TryGetValue(t, out mi))
                        return mi;
                    DynamicMethod dm = CreateUnpackDynamicMethod(t);
                    return CreateUnpacker(t, dm);
                }
                static string FormatMemberName(MemberInfo m)
                {
                    if (m.MemberType != MemberTypes.Field)
                        return m.Name;
                    int pos;
                    string name = m.Name;
                    if (name[0] == '<' && (pos = name.IndexOf('>')) > 1)
                        name = name.Substring(1, pos - 1); // Auto-Property (\<.+\>) <ab>
                    return name;
                }
                static int _dynamicMethodIdx = 0;
                static DynamicMethod CreateDynamicMethod(Type returnType, Type[] parameterTypes)
                {
                    string name = "_" + Interlocked.Increment(ref _dynamicMethodIdx).ToString();
                    return new DynamicMethod(name, returnType, parameterTypes, true);
                }
                internal static IDictionary<string, int> LookupMemberMapping(Type t)
                {
                    IDictionary<string, int> mapping;
                    lock (UnpackMemberMappings)
                    {
                        if (!UnpackMemberMappings.TryGetValue(t, out mapping))
                        {
                            mapping = new Dictionary<string, int>();
                            UnpackMemberMappings.Add(t, mapping);
                        }
                    }
                    return mapping;
                }
            }
            public sealed class MethodBuilderPacker : PackerBase
            {
                public const string AssemblyName = "MessagePackInternalAssembly";
                static AssemblyName DynamicAsmName;
                static AssemblyBuilder DynamicAsmBuilder;
                static ModuleBuilder DynamicModuleBuilder;
                private static MethodInfo LookupMemberMappingMethod;
                static Dictionary<Type, IDictionary<string, int>> UnpackMemberMappings;
                static MethodBuilderPacker()
                {
                    UnpackMemberMappings = new Dictionary<Type, IDictionary<string, int>>();
                    LookupMemberMappingMethod = typeof(MethodBuilderPacker).GetMethod("LookupMemberMapping", BindingFlags.Static | BindingFlags.NonPublic);
                    DynamicAsmName = new AssemblyName(AssemblyName);
                    DynamicAsmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(DynamicAsmName, AssemblyBuilderAccess.Run);
                    DynamicModuleBuilder = DynamicAsmBuilder.DefineDynamicModule(DynamicAsmName.Name);
                }
                public MethodBuilderPacker()
                    : base()
                {
                }
                protected override Action<MsgPackWriter, T> CreatePacker_Internal<T>()
                {
                    TypeBuilder tb;
                    MethodBuilder mb;
                    CreatePackMethodBuilder(typeof(T), out tb, out mb);
                    _packMethods.Add(typeof(T), mb);
                    CreatePacker(typeof(T), mb);
                    MethodInfo mi = ToCallableMethodInfo(typeof(T), tb, true);
                    return (Action<MsgPackWriter, T>)Delegate.CreateDelegate(typeof(Action<MsgPackWriter, T>), mi);
                }
                protected override Func<MsgPackReader, T> CreateUnpacker_Internal<T>()
                {
                    TypeBuilder tb;
                    MethodBuilder mb;
                    CreateUnpackMethodBuilder(typeof(T), out tb, out mb);
                    _unpackMethods.Add(typeof(T), mb);
                    CreateUnpacker(typeof(T), mb);
                    MethodInfo mi = ToCallableMethodInfo(typeof(T), tb, false);
                    return (Func<MsgPackReader, T>)Delegate.CreateDelegate(typeof(Func<MsgPackReader, T>), mi);
                }
                void CreatePacker(Type t, MethodBuilder mb)
                {
                    ILGenerator il = mb.GetILGenerator();
                    PackILGenerator.EmitPackCode(t, mb, il, LookupMembers, FormatMemberName, LookupPackMethod);
                }
                void CreateUnpacker(Type t, MethodBuilder mb)
                {
                    ILGenerator il = mb.GetILGenerator();
                    PackILGenerator.EmitUnpackCode(t, mb, il, LookupMembers, FormatMemberName, LookupUnpackMethod,
                        LookupMemberMapping, LookupMemberMappingMethod);
                }
                MethodInfo ToCallableMethodInfo(Type t, TypeBuilder tb, bool isPacker)
                {
                    Type type = tb.CreateType();
                    MethodInfo mi = type.GetMethod(isPacker ? "Pack" : "Unpack", BindingFlags.Static | BindingFlags.Public);
                    if (isPacker)
                    {
                        _packMethods[t] = mi;
                    }
                    else
                    {
                        _unpackMethods[t] = mi;
                    }
                    return mi;
                }
                MethodInfo LookupPackMethod(Type t)
                {
                    MethodInfo mi;
                    TypeBuilder tb;
                    MethodBuilder mb;
                    if (_packMethods.TryGetValue(t, out mi))
                        return mi;
                    CreatePackMethodBuilder(t, out tb, out mb);
                    _packMethods.Add(t, mb);
                    CreatePacker(t, mb);
                    return ToCallableMethodInfo(t, tb, true);
                }
                MethodInfo LookupUnpackMethod(Type t)
                {
                    MethodInfo mi;
                    TypeBuilder tb;
                    MethodBuilder mb;
                    if (_unpackMethods.TryGetValue(t, out mi))
                        return mi;
                    CreateUnpackMethodBuilder(t, out tb, out mb);
                    _unpackMethods.Add(t, mb);
                    CreateUnpacker(t, mb);
                    return ToCallableMethodInfo(t, tb, false);
                }
                static string FormatMemberName(MemberInfo m)
                {
                    return m.Name;
                }
                static MemberInfo[] LookupMembers(Type t)
                {
                    BindingFlags baseFlags = BindingFlags.Instance | BindingFlags.Public;
                    List<MemberInfo> list = new List<MemberInfo>();
                    list.AddRange(t.GetFields(baseFlags));
                    // TODO: Add NonSerialized Attribute Filter ?
                    return list.ToArray();
                }
                static void CreatePackMethodBuilder(Type t, out TypeBuilder tb, out MethodBuilder mb)
                {
                    tb = DynamicModuleBuilder.DefineType(t.Name + "PackerType", TypeAttributes.Public);
                    mb = tb.DefineMethod("Pack", MethodAttributes.Static | MethodAttributes.Public, typeof(void), new Type[] { typeof(MsgPackWriter), t });
                }
                static void CreateUnpackMethodBuilder(Type t, out TypeBuilder tb, out MethodBuilder mb)
                {
                    tb = DynamicModuleBuilder.DefineType(t.Name + "UnpackerType", TypeAttributes.Public);
                    mb = tb.DefineMethod("Unpack", MethodAttributes.Static | MethodAttributes.Public, t, new Type[] { typeof(MsgPackReader) });
                }
                internal static IDictionary<string, int> LookupMemberMapping(Type t)
                {
                    IDictionary<string, int> mapping;
                    lock (UnpackMemberMappings)
                    {
                        if (!UnpackMemberMappings.TryGetValue(t, out mapping))
                        {
                            mapping = new Dictionary<string, int>();
                            UnpackMemberMappings.Add(t, mapping);
                        }
                    }
                    return mapping;
                }
            }
            #endregion
            #region default pack/unpack methods
            internal static class DefaultPackMethods
            {
                public static void Register(Dictionary<Type, MethodInfo> packMethods, Dictionary<Type, MethodInfo> unpackMethods)
                {
                    RegisterPackMethods(packMethods);
                    RegisterUnpackMethods(unpackMethods);
                }
                #region Pack
                static void RegisterPackMethods(Dictionary<Type, MethodInfo> packMethods)
                {
                    Type type = typeof(DefaultPackMethods);
                    MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.NonPublic);
                    string methodName = "Pack";
                    for (int i = 0; i < methods.Length; i++)
                    {
                        if (!methodName.Equals(methods[i].Name))
                        {
                            continue;
                        }
                        ParameterInfo[] parameters = methods[i].GetParameters();
                        if (parameters.Length != 2 || parameters[0].ParameterType != typeof(MsgPackWriter))
                        {
                            continue;
                        }
                        packMethods.Add(parameters[1].ParameterType, methods[i]);
                    }
                }
                internal static void Pack(MsgPackWriter writer, string x)
                {
                    if (x == null)
                    {
                        writer.WriteNil();
                    }
                    else
                    {
                        writer.Write(x, false);
                    }
                }
                #endregion
                #region Unpack
                static void RegisterUnpackMethods(Dictionary<Type, MethodInfo> unpackMethods)
                {
                    BindingFlags flags = BindingFlags.Static | BindingFlags.NonPublic;
                    Type type = typeof(DefaultPackMethods);
                    MethodInfo mi = type.GetMethod("Unpack_Signed", flags);
                    unpackMethods.Add(typeof(sbyte), mi);
                    unpackMethods.Add(typeof(short), mi);
                    unpackMethods.Add(typeof(int), mi);
                    mi = type.GetMethod("Unpack_Signed64", flags);
                    unpackMethods.Add(typeof(long), mi);
                    mi = type.GetMethod("Unpack_Unsigned", flags);
                    unpackMethods.Add(typeof(byte), mi);
                    unpackMethods.Add(typeof(ushort), mi);
                    unpackMethods.Add(typeof(char), mi);
                    unpackMethods.Add(typeof(uint), mi);
                    mi = type.GetMethod("Unpack_Unsigned64", flags);
                    unpackMethods.Add(typeof(ulong), mi);
                    mi = type.GetMethod("Unpack_Boolean", flags);
                    unpackMethods.Add(typeof(bool), mi);
                    mi = type.GetMethod("Unpack_Float", flags);
                    unpackMethods.Add(typeof(float), mi);
                    mi = type.GetMethod("Unpack_Double", flags);
                    unpackMethods.Add(typeof(double), mi);
                    mi = type.GetMethod("Unpack_String", flags);
                    unpackMethods.Add(typeof(string), mi);
                }
                internal static int Unpack_Signed(MsgPackReader reader)
                {
                    if (!reader.Read() || !reader.IsSigned())
                        UnpackFailed();
                    return reader.ValueSigned;
                }
                internal static long Unpack_Signed64(MsgPackReader reader)
                {
                    if (!reader.Read())
                    {
                        UnpackFailed();
                    }
                    if (reader.IsSigned())
                    {
                        return reader.ValueSigned;
                    }
                    if (reader.IsSigned64())
                    {
                        return reader.ValueSigned64;
                    }
                    UnpackFailed();
                    return 0; // unused
                }
                internal static uint Unpack_Unsigned(MsgPackReader reader)
                {
                    if (!reader.Read() || !reader.IsUnsigned())
                        UnpackFailed();
                    return reader.ValueUnsigned;
                }
                internal static ulong Unpack_Unsigned64(MsgPackReader reader)
                {
                    if (!reader.Read())
                        UnpackFailed();
                    if (reader.IsUnsigned())
                        return reader.ValueUnsigned;
                    if (reader.IsUnsigned64())
                        return reader.ValueUnsigned64;
                    UnpackFailed();
                    return 0; // unused
                }
                internal static bool Unpack_Boolean(MsgPackReader reader)
                {
                    if (!reader.Read() || !reader.IsBoolean())
                        UnpackFailed();
                    return reader.ValueBoolean;
                }
                internal static float Unpack_Float(MsgPackReader reader)
                {
                    if (!reader.Read() || reader.Type != TypePrefixes.Float)
                        UnpackFailed();
                    return reader.ValueFloat;
                }
                internal static double Unpack_Double(MsgPackReader reader)
                {
                    if (!reader.Read() || reader.Type != TypePrefixes.Double)
                        UnpackFailed();
                    return reader.ValueDouble;
                }
                internal static string Unpack_String(MsgPackReader reader)
                {
                    if (!reader.Read() || !reader.IsRaw())
                        UnpackFailed();
                    return reader.ReadRawString();
                }
                internal static void UnpackFailed()
                {
                    throw new FormatException();
                }
                #endregion
            }
            #endregion
        }
    }
    namespace MsgPack
    {
        //
        // Copyright 2011 Kazuki Oikawa
        //
        // Licensed under the Apache License, Version 2.0 (the "License");
        // you may not use this file except in compliance with the License.
        // You may obtain a copy of the License at
        //
        //   http://www.apache.org/licenses/LICENSE-2.0
        //
        // Unless required by applicable law or agreed to in writing, software
        // distributed under the License is distributed on an "AS IS" BASIS,
        // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        // See the License for the specific language governing permissions and
        // limitations under the License.
        //
        using System;
        using System.Collections;
        using System.Collections.Generic;
        using System.IO;
        using System.Reflection;
        public class BoxingPacker
        {
            static Type KeyValuePairDefinitionType;
            static BoxingPacker()
            {
                KeyValuePairDefinitionType = typeof(KeyValuePair<object, object>).GetGenericTypeDefinition();
            }
            public void Pack(Stream strm, object o)
            {
                MsgPackWriter writer = new MsgPackWriter(strm);
                Pack(writer, o);
            }
            public byte[] Pack(object o)
            {
                using (MemoryStream ms = new MemoryStream())
                {
                    Pack(ms, o);
                    return ms.ToArray();
                }
            }
            void Pack(MsgPackWriter writer, object o)
            {
                if (o == null)
                {
                    writer.WriteNil();
                    return;
                }
                Type t = o.GetType();
                if (t.IsPrimitive)
                {
                    if (t.Equals(typeof(int))) writer.Write((int)o);
                    else if (t.Equals(typeof(uint))) writer.Write((uint)o);
                    else if (t.Equals(typeof(float))) writer.Write((float)o);
                    else if (t.Equals(typeof(double))) writer.Write((double)o);
                    else if (t.Equals(typeof(long))) writer.Write((long)o);
                    else if (t.Equals(typeof(ulong))) writer.Write((ulong)o);
                    else if (t.Equals(typeof(bool))) writer.Write((bool)o);
                    else if (t.Equals(typeof(byte))) writer.Write((byte)o);
                    else if (t.Equals(typeof(sbyte))) writer.Write((sbyte)o);
                    else if (t.Equals(typeof(short))) writer.Write((short)o);
                    else if (t.Equals(typeof(ushort))) writer.Write((ushort)o);
                    else throw new NotSupportedException();  // char?
                    return;
                }
                IDictionary dic = o as IDictionary;
                if (dic != null)
                {
                    writer.WriteMapHeader(dic.Count);
                    foreach (System.Collections.DictionaryEntry e in dic)
                    {
                        Pack(writer, e.Key);
                        Pack(writer, e.Value);
                    }
                    return;
                }
                if (t.IsArray)
                {
                    Array ary = (Array)o;
                    Type et = t.GetElementType();
                    // KeyValuePair<K,V>[] (Map Type)
                    if (et.IsGenericType && et.GetGenericTypeDefinition().Equals(KeyValuePairDefinitionType))
                    {
                        PropertyInfo propKey = et.GetProperty("Key");
                        PropertyInfo propValue = et.GetProperty("Value");
                        writer.WriteMapHeader(ary.Length);
                        for (int i = 0; i < ary.Length; i++)
                        {
                            object e = ary.GetValue(i);
                            Pack(writer, propKey.GetValue(e, null));
                            Pack(writer, propValue.GetValue(e, null));
                        }
                        return;
                    }
                    // Array
                    writer.WriteArrayHeader(ary.Length);
                    for (int i = 0; i < ary.Length; i++)
                        Pack(writer, ary.GetValue(i));
                    return;
                }
            }
            public object Unpack(Stream strm)
            {
                MsgPackReader reader = new MsgPackReader(strm);
                return Unpack(reader);
            }
            public object Unpack(byte[] buf, int offset, int size)
            {
                using (MemoryStream ms = new MemoryStream(buf, offset, size))
                {
                    return Unpack(ms);
                }
            }
            public object Unpack(byte[] buf)
            {
                return Unpack(buf, 0, buf.Length);
            }
            object Unpack(MsgPackReader reader)
            {
                if (!reader.Read())
                {
                    throw new FormatException();
                }
                switch (reader.Type)
                {
                    case TypePrefixes.PositiveFixNum:
                    case TypePrefixes.NegativeFixNum:
                    case TypePrefixes.Int8:
                    case TypePrefixes.Int16:
                    case TypePrefixes.Int32:
                        return reader.ValueSigned;
                    case TypePrefixes.Int64:
                        return reader.ValueSigned64;
                    case TypePrefixes.UInt8:
                    case TypePrefixes.UInt16:
                    case TypePrefixes.UInt32:
                        return reader.ValueUnsigned;
                    case TypePrefixes.UInt64:
                        return reader.ValueUnsigned64;
                    case TypePrefixes.True:
                        return true;
                    case TypePrefixes.False:
                        return false;
                    case TypePrefixes.Float:
                        return reader.ValueFloat;
                    case TypePrefixes.Double:
                        return reader.ValueDouble;
                    case TypePrefixes.Nil:
                        return null;
                    case TypePrefixes.FixRaw:
                    case TypePrefixes.Raw16:
                    case TypePrefixes.Raw32:
                        byte[] raw = new byte[reader.Length];
                        reader.ReadValueRaw(raw, 0, raw.Length);
                        return raw;
                    case TypePrefixes.FixArray:
                    case TypePrefixes.Array16:
                    case TypePrefixes.Array32:
                        object[] ary = new object[reader.Length];
                        for (int i = 0; i < ary.Length; i++)
                            ary[i] = Unpack(reader);
                        return ary;
                    case TypePrefixes.FixMap:
                    case TypePrefixes.Map16:
                    case TypePrefixes.Map32:
                        IDictionary<object, object> dic = new Dictionary<object, object>((int)reader.Length);
                        int count = (int)reader.Length;
                        for (int i = 0; i < count; i++)
                        {
                            object k = Unpack(reader);
                            object v = Unpack(reader);
                            dic.Add(k, v);
                        }
                        return dic;
                    default:
                        throw new FormatException();
                }
            }
        }
    }
    namespace MsgPack.Compiler
    {
        //
        // Copyright 2011 Kazuki Oikawa
        //
        // Licensed under the Apache License, Version 2.0 (the "License");
        // you may not use this file except in compliance with the License.
        // You may obtain a copy of the License at
        //
        //   http://www.apache.org/licenses/LICENSE-2.0
        //
        // Unless required by applicable law or agreed to in writing, software
        // distributed under the License is distributed on an "AS IS" BASIS,
        // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        // See the License for the specific language governing permissions and
        // limitations under the License.
        //
        public enum VariableType
        {
            Local,
            Arg
        }
    }
    namespace MsgPack.Compiler
    {
        //
        // Copyright 2011 Kazuki Oikawa
        //
        // Licensed under the Apache License, Version 2.0 (the "License");
        // you may not use this file except in compliance with the License.
        // You may obtain a copy of the License at
        //
        //   http://www.apache.org/licenses/LICENSE-2.0
        //
        // Unless required by applicable law or agreed to in writing, software
        // distributed under the License is distributed on an "AS IS" BASIS,
        // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        // See the License for the specific language governing permissions and
        // limitations under the License.
        //
        using System.Reflection.Emit;
        public class Variable
        {
            Variable(VariableType type, int index)
            {
                this.VarType = type;
                this.Index = index;
            }
            public static Variable CreateLocal(LocalBuilder local)
            {
                return new Variable(VariableType.Local, local.LocalIndex);
            }
            public static Variable CreateArg(int idx)
            {
                return new Variable(VariableType.Arg, idx);
            }
            public VariableType VarType { get; set; }
            public int Index { get; set; }
        }
    }
    namespace MsgPack.Compiler
    {
        //
        // Copyright 2011 Kazuki Oikawa
        //
        // Licensed under the Apache License, Version 2.0 (the "License");
        // you may not use this file except in compliance with the License.
        // You may obtain a copy of the License at
        //
        //   http://www.apache.org/licenses/LICENSE-2.0
        //
        // Unless required by applicable law or agreed to in writing, software
        // distributed under the License is distributed on an "AS IS" BASIS,
        // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        // See the License for the specific language governing permissions and
        // limitations under the License.
        //
        using System;
        using System.Collections.Generic;
        using System.Reflection;
        using System.Reflection.Emit;
        using System.Runtime.Serialization;
        static class PackILGenerator
        {
            #region Pack IL Generator
            public static void EmitPackCode
                            (
                                Type type
                                , MethodInfo mi
                                , ILGenerator il
                                , Func<Type, MemberInfo[]> targetMemberSelector
                                , Func<MemberInfo, string> memberNameFormatter
                                , Func<Type, MethodInfo> lookupPackMethod
                            )
            {
                if (type.IsPrimitive || type.IsInterface)
                {
                    throw new NotSupportedException();
                }
                Variable arg_writer = Variable.CreateArg(0);
                Variable arg_obj = Variable.CreateArg(1);
                Variable local_i = Variable.CreateLocal(il.DeclareLocal(typeof(int)));
                if (!type.IsValueType)
                {
                    // null check
                    Label notNullLabel = il.DefineLabel();
                    il.EmitLd(arg_obj);
                    il.Emit(OpCodes.Brtrue_S, notNullLabel);
                    il.EmitLd(arg_writer);
                    il.Emit(OpCodes.Call, typeof(MsgPackWriter).GetMethod("WriteNil", new Type[0]));
                    il.Emit(OpCodes.Ret);
                    il.MarkLabel(notNullLabel);
                }
                if (type.IsArray)
                {
                    EmitPackArrayCode(mi, il, type, arg_writer, arg_obj, local_i, lookupPackMethod);
                    goto FinallyProcess;
                }
                // MsgPackWriter.WriteMapHeader
                MemberInfo[] members = targetMemberSelector(type);
                il.EmitLd(arg_writer);
                il.EmitLdc(members.Length);
                il.Emit(OpCodes.Callvirt, typeof(MsgPackWriter).GetMethod("WriteMapHeader", new Type[] { typeof(int) }));
                for (int i = 0; i < members.Length; i++)
                {
                    MemberInfo m = members[i];
                    Type mt = m.GetMemberType();
                    // write field-name
                    il.EmitLd(arg_writer);
                    il.EmitLdstr(memberNameFormatter(m));
                    il.EmitLd_True();
                    il.Emit(OpCodes.Call, typeof(MsgPackWriter).GetMethod("Write", new Type[] { typeof(string), typeof(bool) }));
                    // write value
                    EmitPackMemberValueCode(mt, il, arg_writer, arg_obj, m, null, type, mi, lookupPackMethod);
                }
            FinallyProcess:
                il.Emit(OpCodes.Ret);
            }
            static void EmitPackArrayCode
                                (
                                    MethodInfo mi
                                    , ILGenerator il
                                    , Type t
                                    , Variable var_writer
                                    , Variable var_obj
                                    , Variable var_loop
                                    , Func<Type, MethodInfo> lookupPackMethod
                                )
            {
                Type et = t.GetElementType();
                il.EmitLd(var_writer, var_obj);
                il.Emit(OpCodes.Ldlen);
                il.Emit(OpCodes.Call, typeof(MsgPackWriter).GetMethod("WriteArrayHeader", new Type[] { typeof(int) }));
                Label beginLabel = il.DefineLabel();
                Label exprLabel = il.DefineLabel();
                // for-loop: init loop counter
                il.EmitLdc(0);
                il.EmitSt(var_loop);
                // jump
                il.Emit(OpCodes.Br_S, exprLabel);
                // mark begin-label
                il.MarkLabel(beginLabel);
                // write element
                EmitPackMemberValueCode(et, il, var_writer, var_obj, null, var_loop, t, mi, lookupPackMethod);
                // increment loop-counter
                il.EmitLd(var_loop);
                il.Emit(OpCodes.Ldc_I4_1);
                il.Emit(OpCodes.Add);
                il.EmitSt(var_loop);
                // mark expression label
                il.MarkLabel(exprLabel);
                // expression
                il.EmitLd(var_loop, var_obj);
                il.Emit(OpCodes.Ldlen);
                il.Emit(OpCodes.Blt_S, beginLabel);
            }
            /// <param name="m">(optional)</param>
            /// <param name="elementIdx">(optional)</param>
            static void EmitPackMemberValueCode(Type type, ILGenerator il, Variable var_writer, Variable var_obj,
                MemberInfo m, Variable elementIdx, Type currentType, MethodInfo currentMethod, Func<Type, MethodInfo> lookupPackMethod)
            {
                MethodInfo mi;
                il.EmitLd(var_writer, var_obj);
                if (m != null)
                    il.EmitLdMember(m);
                if (elementIdx != null)
                {
                    il.EmitLd(elementIdx);
                    il.Emit(OpCodes.Ldelem, type);
                }
                if (type.IsPrimitive)
                {
                    mi = typeof(MsgPackWriter).GetMethod("Write", new Type[] { type });
                }
                else
                {
                    if (currentType == type)
                    {
                        mi = currentMethod;
                    }
                    else
                    {
                        mi = lookupPackMethod(type);
                    }
                }
                il.Emit(OpCodes.Call, mi);
            }
            #endregion
            #region Unpack IL Generator
            public static void EmitUnpackCode(Type type, MethodInfo mi, ILGenerator il,
                Func<Type, MemberInfo[]> targetMemberSelector,
                Func<MemberInfo, string> memberNameFormatter,
                Func<Type, MethodInfo> lookupUnpackMethod,
                Func<Type, IDictionary<string, int>> lookupMemberMapping,
                MethodInfo lookupMemberMappingMethod)
            {
                if (type.IsArray)
                {
                    EmitUnpackArrayCode(type, mi, il, targetMemberSelector, memberNameFormatter, lookupUnpackMethod);
                }
                else
                {
                    EmitUnpackMapCode(type, mi, il, targetMemberSelector, memberNameFormatter, lookupUnpackMethod, lookupMemberMapping, lookupMemberMappingMethod);
                }
            }
            static void EmitUnpackMapCode(Type type, MethodInfo mi, ILGenerator il,
                Func<Type, MemberInfo[]> targetMemberSelector,
                Func<MemberInfo, string> memberNameFormatter,
                Func<Type, MethodInfo> lookupUnpackMethod,
                Func<Type, IDictionary<string, int>> lookupMemberMapping,
                MethodInfo lookupMemberMappingMethod)
            {
                MethodInfo failedMethod = typeof(PackILGenerator).GetMethod("UnpackFailed", BindingFlags.Static | BindingFlags.NonPublic);
                MemberInfo[] members = targetMemberSelector(type);
                IDictionary<string, int> member_mapping = lookupMemberMapping(type);
                for (int i = 0; i < members.Length; i++)
                    member_mapping.Add(memberNameFormatter(members[i]), i);
                Variable msgpackReader = Variable.CreateArg(0);
                Variable obj = Variable.CreateLocal(il.DeclareLocal(type));
                Variable num_of_fields = Variable.CreateLocal(il.DeclareLocal(typeof(int)));
                Variable loop_idx = Variable.CreateLocal(il.DeclareLocal(typeof(int)));
                Variable mapping = Variable.CreateLocal(il.DeclareLocal(typeof(IDictionary<string, int>)));
                Variable switch_idx = Variable.CreateLocal(il.DeclareLocal(typeof(int)));
                Variable var_type = Variable.CreateLocal(il.DeclareLocal(typeof(Type)));
                // if (!MsgPackReader.Read()) UnpackFailed ();
                // if (MsgPackReader.Type == TypePrefixes.Nil) return null;
                // if (!MsgPackReader.IsMap ()) UnpackFailed ();
                EmitUnpackReadAndTypeCheckCode(il, msgpackReader, typeof(MsgPackReader).GetMethod("IsMap"), failedMethod, true);
                // type = typeof (T)
                il.Emit(OpCodes.Ldtoken, type);
                il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));
                il.EmitSt(var_type);
                // mapping = LookupMemberMapping (typeof (T))
                il.EmitLd(var_type);
                il.Emit(OpCodes.Call, lookupMemberMappingMethod);
                il.EmitSt(mapping);
                // object o = FormatterServices.GetUninitializedObject (Type);
                il.EmitLd(var_type);
                il.Emit(OpCodes.Call, typeof(FormatterServices).GetMethod("GetUninitializedObject"));
                il.Emit(OpCodes.Castclass, type);
                il.EmitSt(obj);
                // num_of_fields = (int)reader.Length
                il.EmitLd(msgpackReader);
                il.Emit(OpCodes.Call, typeof(MsgPackReader).GetProperty("Length").GetGetMethod());
                il.EmitSt(num_of_fields);
                // Loop labels
                Label lblLoopStart = il.DefineLabel();
                Label lblLoopExpr = il.DefineLabel();
                // i = 0;
                il.EmitLdc(0);
                il.EmitSt(loop_idx);
                il.Emit(OpCodes.Br, lblLoopExpr);
                il.MarkLabel(lblLoopStart);
                /* process */
                // if (!MsgPackReader.Read() || !MsgPackReader.IsRaw()) UnpackFailed();
                EmitUnpackReadAndTypeCheckCode(il, msgpackReader, typeof(MsgPackReader).GetMethod("IsRaw"), failedMethod, false);
                // MsgPackReader.ReadRawString ()
                // if (!Dictionary.TryGetValue (,)) UnpackFailed();
                Label lbl3 = il.DefineLabel();
                il.EmitLd(mapping);
                il.EmitLd(msgpackReader);
                il.Emit(OpCodes.Call, typeof(MsgPackReader).GetMethod("ReadRawString", new Type[0]));
                il.Emit(OpCodes.Ldloca_S, (byte)switch_idx.Index);
                il.Emit(OpCodes.Callvirt, typeof(IDictionary<string, int>).GetMethod("TryGetValue"));
                il.Emit(OpCodes.Brtrue, lbl3);
                il.Emit(OpCodes.Call, failedMethod);
                il.MarkLabel(lbl3);
                // switch
                Label[] switchCases = new Label[members.Length];
                for (int i = 0; i < switchCases.Length; i++)
                    switchCases[i] = il.DefineLabel();
                Label switchCaseEndLabel = il.DefineLabel();
                il.EmitLd(switch_idx);
                il.Emit(OpCodes.Switch, switchCases);
                il.Emit(OpCodes.Call, failedMethod);
                for (int i = 0; i < switchCases.Length; i++)
                {
                    il.MarkLabel(switchCases[i]);
                    MemberInfo minfo = members[i];
                    Type mt = minfo.GetMemberType();
                    MethodInfo unpack_method = lookupUnpackMethod(mt);
                    il.EmitLd(obj);
                    il.EmitLd(msgpackReader);
                    il.Emit(OpCodes.Call, unpack_method);
                    il.EmitStMember(minfo);
                    il.Emit(OpCodes.Br, switchCaseEndLabel);
                }
                il.MarkLabel(switchCaseEndLabel);
                // i ++
                il.EmitLd(loop_idx);
                il.EmitLdc(1);
                il.Emit(OpCodes.Add);
                il.EmitSt(loop_idx);
                // i < num_of_fields;
                il.MarkLabel(lblLoopExpr);
                il.EmitLd(loop_idx);
                il.EmitLd(num_of_fields);
                il.Emit(OpCodes.Blt, lblLoopStart);
                // return
                il.EmitLd(obj);
                il.Emit(OpCodes.Ret);
            }
            static void EmitUnpackArrayCode(Type arrayType, MethodInfo mi, ILGenerator il,
                Func<Type, MemberInfo[]> targetMemberSelector,
                Func<MemberInfo, string> memberNameFormatter,
                Func<Type, MethodInfo> lookupUnpackMethod)
            {
                Type elementType = arrayType.GetElementType();
                MethodInfo failedMethod = typeof(PackILGenerator).GetMethod("UnpackFailed", BindingFlags.Static | BindingFlags.NonPublic);
                Variable msgpackReader = Variable.CreateArg(0);
                Variable obj = Variable.CreateLocal(il.DeclareLocal(arrayType));
                Variable num_of_elements = Variable.CreateLocal(il.DeclareLocal(typeof(int)));
                Variable loop_idx = Variable.CreateLocal(il.DeclareLocal(typeof(int)));
                Variable type = Variable.CreateLocal(il.DeclareLocal(typeof(Type)));
                // if (!MsgPackReader.Read() || !MsgPackReader.IsArray ()) UnpackFailed ();
                EmitUnpackReadAndTypeCheckCode(il, msgpackReader, typeof(MsgPackReader).GetMethod("IsArray"), failedMethod, true);
                // type = typeof (T)
                il.Emit(OpCodes.Ldtoken, elementType);
                il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));
                il.EmitSt(type);
                // num_of_elements = (int)reader.Length
                il.EmitLd(msgpackReader);
                il.Emit(OpCodes.Call, typeof(MsgPackReader).GetProperty("Length").GetGetMethod());
                il.EmitSt(num_of_elements);
                // object o = Array.CreateInstance (Type, Length);
                il.EmitLd(type);
                il.EmitLd(num_of_elements);
                il.Emit(OpCodes.Call, typeof(Array).GetMethod("CreateInstance", new Type[] { typeof(Type), typeof(int) }));
                il.Emit(OpCodes.Castclass, arrayType);
                il.EmitSt(obj);
                // Unpack element method
                MethodInfo unpack_method = lookupUnpackMethod(elementType);
                // Loop labels
                Label lblLoopStart = il.DefineLabel();
                Label lblLoopExpr = il.DefineLabel();
                // i = 0;
                il.EmitLdc(0);
                il.EmitSt(loop_idx);
                il.Emit(OpCodes.Br, lblLoopExpr);
                il.MarkLabel(lblLoopStart);
                /* process */
                il.EmitLd(obj, loop_idx);
                il.EmitLd(msgpackReader);
                il.Emit(OpCodes.Call, unpack_method);
                il.Emit(OpCodes.Stelem, elementType);
                // i ++
                il.EmitLd(loop_idx);
                il.EmitLdc(1);
                il.Emit(OpCodes.Add);
                il.EmitSt(loop_idx);
                // i < num_of_fields;
                il.MarkLabel(lblLoopExpr);
                il.EmitLd(loop_idx);
                il.EmitLd(num_of_elements);
                il.Emit(OpCodes.Blt, lblLoopStart);
                // return
                il.EmitLd(obj);
                il.Emit(OpCodes.Ret);
            }
            static void EmitUnpackReadAndTypeCheckCode(ILGenerator il, Variable msgpackReader, MethodInfo typeCheckMethod, MethodInfo failedMethod, bool nullCheckAndReturn)
            {
                Label lblFailed = il.DefineLabel();
                Label lblNullReturn = nullCheckAndReturn ? il.DefineLabel() : default(Label);
                Label lblPassed = il.DefineLabel();
                il.EmitLd(msgpackReader);
                il.Emit(OpCodes.Call, typeof(MsgPackReader).GetMethod("Read"));
                il.Emit(OpCodes.Brfalse_S, lblFailed);
                if (nullCheckAndReturn)
                {
                    il.EmitLd(msgpackReader);
                    il.Emit(OpCodes.Call, typeof(MsgPackReader).GetProperty("Type").GetGetMethod());
                    il.EmitLdc((int)TypePrefixes.Nil);
                    il.Emit(OpCodes.Beq_S, lblNullReturn);
                }
                il.EmitLd(msgpackReader);
                il.Emit(OpCodes.Call, typeCheckMethod);
                il.Emit(OpCodes.Brtrue_S, lblPassed);
                il.Emit(OpCodes.Br, lblFailed);
                if (nullCheckAndReturn)
                {
                    il.MarkLabel(lblNullReturn);
                    il.Emit(OpCodes.Ldnull);
                    il.Emit(OpCodes.Ret);
                }
                il.MarkLabel(lblFailed);
                il.Emit(OpCodes.Call, failedMethod);
                il.MarkLabel(lblPassed);
            }
            /// <summary>Exception Helper</summary>
            internal static void UnpackFailed()
            {
                throw new FormatException();
            }
            #endregion
            #region Misc
            static Type GetMemberType(this MemberInfo mi)
            {
                if (mi.MemberType == MemberTypes.Field)
                    return ((FieldInfo)mi).FieldType;
                if (mi.MemberType == MemberTypes.Property)
                    return ((PropertyInfo)mi).PropertyType;
                throw new ArgumentException();
            }
            #endregion
        }
    }
    namespace MsgPack.Compiler
    {
        //
        // Copyright 2011 Kazuki Oikawa
        //
        // Licensed under the Apache License, Version 2.0 (the "License");
        // you may not use this file except in compliance with the License.
        // You may obtain a copy of the License at
        //
        //   http://www.apache.org/licenses/LICENSE-2.0
        //
        // Unless required by applicable law or agreed to in writing, software
        // distributed under the License is distributed on an "AS IS" BASIS,
        // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        // See the License for the specific language governing permissions and
        // limitations under the License.
        //
        using System;
        using System.Reflection;
        using System.Reflection.Emit;
        public static class EmitExtensions
        {
            public static void EmitLd(this ILGenerator il, Variable v)
            {
                switch (v.VarType)
                {
                    case VariableType.Arg:
                        EmitLdarg(il, v);
                        break;
                    case VariableType.Local:
                        EmitLdloc(il, v);
                        break;
                    default:
                        throw new ArgumentException();
                }
            }
            public static void EmitLd(this ILGenerator il, params Variable[] list)
            {
                for (int i = 0; i < list.Length; i++)
                    EmitLd(il, list[i]);
            }
            public static void EmitLdarg(this ILGenerator il, Variable v)
            {
                if (v.VarType != VariableType.Arg)
                    throw new ArgumentException();
                switch (v.Index)
                {
                    case 0: il.Emit(OpCodes.Ldarg_0); return;
                    case 1: il.Emit(OpCodes.Ldarg_1); return;
                    case 2: il.Emit(OpCodes.Ldarg_2); return;
                    case 3: il.Emit(OpCodes.Ldarg_3); return;
                }
                if (v.Index <= byte.MaxValue)
                {
                    il.Emit(OpCodes.Ldarg_S, (byte)v.Index);
                }
                else if (v.Index <= short.MaxValue)
                {
                    il.Emit(OpCodes.Ldarg, v.Index);
                }
                else
                {
                    throw new FormatException();
                }
            }
            public static void EmitLdloc(this ILGenerator il, Variable v)
            {
                if (v.VarType != VariableType.Local)
                    throw new ArgumentException();
                switch (v.Index)
                {
                    case 0: il.Emit(OpCodes.Ldloc_0); return;
                    case 1: il.Emit(OpCodes.Ldloc_1); return;
                    case 2: il.Emit(OpCodes.Ldloc_2); return;
                    case 3: il.Emit(OpCodes.Ldloc_3); return;
                }
                if (v.Index <= byte.MaxValue)
                {
                    il.Emit(OpCodes.Ldloc_S, (byte)v.Index);
                }
                else if (v.Index <= short.MaxValue)
                {
                    il.Emit(OpCodes.Ldloc, v.Index);
                }
                else
                {
                    throw new FormatException();
                }
            }
            public static void EmitSt(this ILGenerator il, Variable v)
            {
                switch (v.VarType)
                {
                    case VariableType.Arg:
                        EmitStarg(il, v);
                        break;
                    case VariableType.Local:
                        EmitStloc(il, v);
                        break;
                    default:
                        throw new ArgumentException();
                }
            }
            public static void EmitStarg(this ILGenerator il, Variable v)
            {
                if (v.VarType != VariableType.Arg)
                    throw new ArgumentException();
                if (v.Index <= byte.MaxValue)
                {
                    il.Emit(OpCodes.Starg_S, (byte)v.Index);
                }
                else if (v.Index <= short.MaxValue)
                {
                    il.Emit(OpCodes.Starg, v.Index);
                }
                else
                {
                    throw new FormatException();
                }
            }
            public static void EmitStloc(this ILGenerator il, Variable v)
            {
                if (v.VarType != VariableType.Local)
                    throw new ArgumentException();
                switch (v.Index)
                {
                    case 0: il.Emit(OpCodes.Stloc_0); return;
                    case 1: il.Emit(OpCodes.Stloc_1); return;
                    case 2: il.Emit(OpCodes.Stloc_2); return;
                    case 3: il.Emit(OpCodes.Stloc_3); return;
                }
                if (v.Index <= byte.MaxValue)
                {
                    il.Emit(OpCodes.Stloc_S, (byte)v.Index);
                }
                else if (v.Index <= short.MaxValue)
                {
                    il.Emit(OpCodes.Stloc, v.Index);
                }
                else
                {
                    throw new FormatException();
                }
            }
            public static void EmitLdc(this ILGenerator il, int v)
            {
                switch (v)
                {
                    case 0: il.Emit(OpCodes.Ldc_I4_0); return;
                    case 1: il.Emit(OpCodes.Ldc_I4_1); return;
                    case 2: il.Emit(OpCodes.Ldc_I4_2); return;
                    case 3: il.Emit(OpCodes.Ldc_I4_3); return;
                    case 4: il.Emit(OpCodes.Ldc_I4_4); return;
                    case 5: il.Emit(OpCodes.Ldc_I4_5); return;
                    case 6: il.Emit(OpCodes.Ldc_I4_6); return;
                    case 7: il.Emit(OpCodes.Ldc_I4_7); return;
                    case 8: il.Emit(OpCodes.Ldc_I4_8); return;
                    case -1: il.Emit(OpCodes.Ldc_I4_M1); return;
                }
                if (v <= sbyte.MaxValue && v >= sbyte.MinValue)
                {
                    il.Emit(OpCodes.Ldc_I4_S, (sbyte)v);
                }
                else
                {
                    il.Emit(OpCodes.Ldc_I4, v);
                }
            }
            public static void EmitLd_False(this ILGenerator il)
            {
                il.Emit(OpCodes.Ldc_I4_1);
            }
            public static void EmitLd_True(this ILGenerator il)
            {
                il.Emit(OpCodes.Ldc_I4_1);
            }
            public static void EmitLdstr(this ILGenerator il, string v)
            {
                il.Emit(OpCodes.Ldstr, v);
            }
            public static void EmitLdMember(this ILGenerator il, MemberInfo m)
            {
                if (m.MemberType == MemberTypes.Field)
                {
                    il.Emit(OpCodes.Ldfld, (FieldInfo)m);
                }
                else if (m.MemberType == MemberTypes.Property)
                {
                    il.Emit(OpCodes.Callvirt, ((PropertyInfo)m).GetGetMethod(true));
                }
                else
                {
                    throw new ArgumentException();
                }
            }
            public static void EmitStMember(this ILGenerator il, MemberInfo m)
            {
                if (m.MemberType == MemberTypes.Field)
                {
                    il.Emit(OpCodes.Stfld, (FieldInfo)m);
                }
                else if (m.MemberType == MemberTypes.Property)
                {
                    il.Emit(OpCodes.Callvirt, ((PropertyInfo)m).GetSetMethod(true));
                }
                else
                {
                    throw new ArgumentException();
                }
            }
        }
    }
    
    
  • 相关阅读:
    GridView多表头固定+分组+总计
    ajaxpro.2.dll使用【转帖】
    表达式计算易错题
    uclibc下使用libcurl的段错误(缺少hosts文件)
    《java.util.concurrent 包源码阅读》01 源码包的结构
    Linux学习笔记【2】Install Software under RedHat enterprise 5.4
    Windows语言包的那些事
    Let outlook work background when it is minimal
    DB2 Error Message
    db2 系统表信息
  • 原文地址:https://www.cnblogs.com/Microshaoft/p/2428996.html
Copyright © 2020-2023  润新知