예제 #1
0
        private Union CreateUnion(Type t)
        {
            Union u = new Union();

            u.TagReader = FSharpFunc <object, int> .ToConverter(FSharpValue.PreComputeUnionTagReader(t, null));

            u.Cases = new List <UnionCase>();

            UnionCaseInfo[] cases = FSharpType.GetUnionCases(t, null);

            foreach (UnionCaseInfo unionCaseInfo in cases)
            {
                UnionCase unionCase = new UnionCase();
                unionCase.Tag         = unionCaseInfo.Tag;
                unionCase.Name        = unionCaseInfo.Name;
                unionCase.Fields      = unionCaseInfo.GetFields();
                unionCase.FieldReader = FSharpFunc <object, object[]> .ToConverter(FSharpValue.PreComputeUnionReader(unionCaseInfo, null));

                unionCase.Constructor = FSharpFunc <object[], object> .ToConverter(FSharpValue.PreComputeUnionConstructor(unionCaseInfo, null));

                u.Cases.Add(unionCase);
            }

            return(u);
        }
        private Union CreateUnion(Type t)
        {
            Union u = new Union();

            u.TagReader = (s) => FSharpValue.PreComputeUnionTagReader(t, null).Invoke(s);
            u.Cases     = new List <UnionCase>();

            UnionCaseInfo[] cases = FSharpType.GetUnionCases(t, null);

            foreach (UnionCaseInfo unionCaseInfo in cases)
            {
                UnionCase unionCase = new UnionCase();
                unionCase.Tag         = unionCaseInfo.Tag;
                unionCase.Name        = unionCaseInfo.Name;
                unionCase.Fields      = unionCaseInfo.GetFields();
                unionCase.FieldReader = (s) =>
                                        FSharpValue.PreComputeUnionReader(unionCaseInfo, null).Invoke(s);
                unionCase.Constructor = (s) =>
                                        FSharpValue.PreComputeUnionConstructor(unionCaseInfo, null).Invoke(s);

                u.Cases.Add(unionCase);
            }

            return(u);
        }
        static TypeInfo BuildType(Type type)
        {
            var ti = type.GetTypeInfo();
            // order by key(important for use jump-table of switch)
            var unionCases = FSharpType.GetUnionCases(type, null).OrderBy(x => x.Tag).ToArray();

            var         formatterType = typeof(IMessagePackFormatter <>).MakeGenericType(type);
            TypeBuilder typeBuilder   = DynamicAssembly.DefineType("MessagePack.FSharp.Formatters." + SubtractFullNameRegex.Replace(type.FullName, string.Empty).Replace(".", "_") + "Formatter" + +Interlocked.Increment(ref nameSequence), TypeAttributes.Public | TypeAttributes.Sealed, null, new[] { formatterType });

            var stringByteKeysFields = new FieldBuilder[unionCases.Length];

            // create map dictionary
            {
                var method = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, Type.EmptyTypes);

                foreach (var unionCase in unionCases)
                {
                    stringByteKeysFields[unionCase.Tag] = typeBuilder.DefineField("stringByteKeysField" + unionCase.Tag, typeof(byte[][]), FieldAttributes.Private | FieldAttributes.InitOnly);
                }

                var il = method.GetILGenerator();
                BuildConstructor(type, unionCases, method, stringByteKeysFields, il);
            }

            {
                var method = typeBuilder.DefineMethod(
                    "Serialize",
                    MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual,
                    returnType: null,
                    parameterTypes: new Type[] { typeof(MessagePackWriter).MakeByRefType(), type, typeof(MessagePackSerializerOptions) });
                method.DefineParameter(1, ParameterAttributes.None, "writer");
                method.DefineParameter(2, ParameterAttributes.None, "value");
                method.DefineParameter(3, ParameterAttributes.None, "options");

                var il = method.GetILGenerator();
                BuildSerialize(type, unionCases, method, stringByteKeysFields, il, 1);
            }
            {
                MethodBuilder method = typeBuilder.DefineMethod(
                    "Deserialize",
                    MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual,
                    type,
                    new Type[] { refMessagePackReader, typeof(MessagePackSerializerOptions) });
                method.DefineParameter(1, ParameterAttributes.None, "reader");
                method.DefineParameter(2, ParameterAttributes.None, "options");

                var il = method.GetILGenerator();
                BuildDeserialize(
                    type,
                    unionCases,
                    method,
                    stringByteKeysFields,
                    il,
                    1); // firstArgIndex:0 is this.
            }

            return(typeBuilder.CreateTypeInfo());
        }
예제 #4
0
        public static object Create <TTypeResolver, T>()
            where TTypeResolver : ITypeResolver, new()
        {
            var t  = typeof(T);
            var ti = t.GetTypeInfo();

            if (!FSharpType.IsUnion(t, null))
            {
                throw new InvalidOperationException("Type must be F# Discriminated Union. " + ti.FullName);
            }

            var unionCases = FSharpType.GetUnionCases(t, null);

            var generateTypeInfo = BuildFormatter(typeof(TTypeResolver), t, unionCases);
            var formatter        = Activator.CreateInstance(generateTypeInfo.AsType());

            return(formatter);
        }
예제 #5
0
        static TypeInfo BuildType(Type type)
        {
            var ti = type.GetTypeInfo();
            // order by key(important for use jump-table of switch)
            var unionCases = FSharpType.GetUnionCases(type, null).OrderBy(x => x.Tag).ToArray();

            var formatterType = typeof(IMessagePackFormatter <>).MakeGenericType(type);
            var typeBuilder   = assembly.ModuleBuilder.DefineType("MessagePack.FSharp.Formatters." + SubtractFullNameRegex.Replace(type.FullName, "").Replace(".", "_") + "Formatter" + +Interlocked.Increment(ref nameSequence), TypeAttributes.Public | TypeAttributes.Sealed, null, new[] { formatterType });

            var stringByteKeysFields = new FieldBuilder[unionCases.Length];

            // create map dictionary
            {
                var method = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, Type.EmptyTypes);

                foreach (var unionCase in unionCases)
                {
                    stringByteKeysFields[unionCase.Tag] = typeBuilder.DefineField("stringByteKeysField" + unionCase.Tag, typeof(byte[][]), FieldAttributes.Private | FieldAttributes.InitOnly);
                }

                var il = method.GetILGenerator();
                BuildConstructor(type, unionCases, method, stringByteKeysFields, il);
            }

            {
                var method = typeBuilder.DefineMethod("Serialize", MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual,
                                                      typeof(int),
                                                      new Type[] { typeof(byte[]).MakeByRefType(), typeof(int), type, typeof(IFormatterResolver) });

                var il = method.GetILGenerator();
                BuildSerialize(type, unionCases, method, stringByteKeysFields, il);
            }
            {
                var method = typeBuilder.DefineMethod("Deserialize", MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Virtual,
                                                      type,
                                                      new Type[] { typeof(byte[]), typeof(int), typeof(IFormatterResolver), typeof(int).MakeByRefType() });

                var il = method.GetILGenerator();
                BuildDeserialize(type, unionCases, method, stringByteKeysFields, il);
            }

            return(typeBuilder.CreateTypeInfo());
        }
예제 #6
0
        /// <summary>
        /// Type情報からデフォルトのインスタンスを生成する.
        /// </summary>
        /// <param name="type">デフォルトインスタンスを生成したいType情報</param>
        /// <returns>Type情報から生成したインスタンス</returns>
        public static object MakeDefault(this Type type)
        {
            var none = FSharpOption <BindingFlags> .None;

            if (type == typeof(int))
            {
                return(default(int));
            }
            if (type == typeof(uint))
            {
                return(default(uint));
            }
            if (type == typeof(short))
            {
                return(default(short));
            }
            if (type == typeof(ushort))
            {
                return(default(ushort));
            }
            if (type == typeof(long))
            {
                return(default(long));
            }
            if (type == typeof(ulong))
            {
                return(default(ulong));
            }
            if (type == typeof(byte))
            {
                return(default(byte));
            }
            if (type == typeof(sbyte))
            {
                return(default(sbyte));
            }
            if (type == typeof(bool))
            {
                return(default(bool));
            }
            if (type == typeof(float))
            {
                return(default(float));
            }
            if (type == typeof(double))
            {
                return(default(double));
            }
            if (type == typeof(decimal))
            {
                return(default(decimal));
            }
            if (type == typeof(char))
            {
                return(default(char));
            }
            if (type == typeof(string))
            {
                return(default(string));
            }
            if (type == typeof(Guid))
            {
                return(default(Guid));
            }
            if (type == typeof(DateTime))
            {
                return(default(DateTime));
            }
            if (type == typeof(DateTimeOffset))
            {
                return(default(DateTimeOffset));
            }
            if (type == typeof(byte[]))
            {
                return(default(byte[]));
            }

            if (type == typeof(int?))
            {
                return(default(int?));
            }
            if (type == typeof(uint?))
            {
                return(default(uint?));
            }
            if (type == typeof(short?))
            {
                return(default(short?));
            }
            if (type == typeof(ushort?))
            {
                return(default(ushort?));
            }
            if (type == typeof(long?))
            {
                return(default(long?));
            }
            if (type == typeof(ulong?))
            {
                return(default(ulong?));
            }
            if (type == typeof(byte?))
            {
                return(default(byte?));
            }
            if (type == typeof(sbyte?))
            {
                return(default(sbyte?));
            }
            if (type == typeof(bool?))
            {
                return(default(bool?));
            }
            if (type == typeof(float?))
            {
                return(default(float?));
            }
            if (type == typeof(double?))
            {
                return(default(double?));
            }
            if (type == typeof(decimal?))
            {
                return(default(decimal?));
            }
            if (type == typeof(char?))
            {
                return(default(char?));
            }
            if (type == typeof(Guid?))
            {
                return(default(Guid?));
            }
            if (type == typeof(DateTime?))
            {
                return(default(DateTime?));
            }
            if (type == typeof(DateTimeOffset?))
            {
                return(default(DateTimeOffset?));
            }

            if (type == typeof(FSharpOption <int>))
            {
                return(FSharpOption <int> .None);
            }
            if (type == typeof(FSharpOption <uint>))
            {
                return(FSharpOption <uint> .None);
            }
            if (type == typeof(FSharpOption <short>))
            {
                return(FSharpOption <short> .None);
            }
            if (type == typeof(FSharpOption <ushort>))
            {
                return(FSharpOption <ushort> .None);
            }
            if (type == typeof(FSharpOption <long>))
            {
                return(FSharpOption <long> .None);
            }
            if (type == typeof(FSharpOption <ulong>))
            {
                return(FSharpOption <ulong> .None);
            }
            if (type == typeof(FSharpOption <byte>))
            {
                return(FSharpOption <byte> .None);
            }
            if (type == typeof(FSharpOption <sbyte>))
            {
                return(FSharpOption <sbyte> .None);
            }
            if (type == typeof(FSharpOption <bool>))
            {
                return(FSharpOption <bool> .None);
            }
            if (type == typeof(FSharpOption <float>))
            {
                return(FSharpOption <float> .None);
            }
            if (type == typeof(FSharpOption <double>))
            {
                return(FSharpOption <double> .None);
            }
            if (type == typeof(FSharpOption <decimal>))
            {
                return(FSharpOption <decimal> .None);
            }
            if (type == typeof(FSharpOption <char>))
            {
                return(FSharpOption <char> .None);
            }
            if (type == typeof(FSharpOption <string>))
            {
                return(FSharpOption <string> .None);
            }
            if (type == typeof(FSharpOption <Guid>))
            {
                return(FSharpOption <Guid> .None);
            }
            if (type == typeof(FSharpOption <DateTime>))
            {
                return(FSharpOption <DateTime> .None);
            }
            if (type == typeof(FSharpOption <DateTimeOffset>))
            {
                return(FSharpOption <DateTimeOffset> .None);
            }
            if (type == typeof(FSharpOption <byte[]>))
            {
                return(FSharpOption <byte[]> .None);
            }

            // Option型(F#)
            //   - FSharpType.IsUnion()でも引っ掛かってしまうので、
            //     それよりも前に判定をする必要がある.
            if (type.IsFsharpOption())
            {
                return(type
                       .GetProperty("None", BindingFlags.Public | BindingFlags.Static)
                       .GetGetMethod()
                       .Invoke(null, null));
            }

            // 判別共用体(F#)
            if (type.IsFsharpDiscriminatedUnions())
            {
                var ctor = FSharpType.GetUnionCases(type, none).FirstOrDefault();
                if (ctor == null)
                {
                    throw new Exception("Invalid discriminated-unions.");
                }
                var ps = ctor.GetFields();
                var qs = new object[ps.Length];
                for (var i = 0; i < ps.Length; i++)
                {
                    qs[i] = ps[i].PropertyType.MakeDefault();
                }

                return(FSharpValue.MakeUnion(ctor, qs, none));
            }

            // 列挙型
            if (type.IsEnum)
            {
                return(type.GetEnumValue(0));
            }

            // 構造体
            if (type.IsValueType)
            {
                return(Activator.CreateInstance(type));
            }

            // クラス
            if (type.IsClass)
            {
                var ctor = type.GetConstructors().FirstOrDefault();

                // publicコンストラクタが存在しない場合、nullを返す
                if (ctor is null)
                {
                    return(null);
                }
                else
                {
                    var ps = ctor.GetParameters();
                    var qs = new object[ps.Length];
                    for (int i = 0; i < ps.Length; i++)
                    {
                        qs[i] = ps[i].ParameterType.MakeDefault();
                    }

#if NET40 || NET45 || NET46 || NET472 || NET48 || NETCOREAPP3_1 || NET5_0
                    return(type.Constructor(qs));
#else
                    return(Activator.CreateInstance(type, qs));
#endif
                }
            }

            throw new ArgumentException("'type' is not supported.");
        }
        public object Resolve(Type memberType, object value)
        {
            var none = FSharpOption <BindingFlags> .None;

            if (memberType == typeof(int))
            {
                return(value is DBNull ? default(int) : value);
            }
            if (memberType == typeof(uint))
            {
                return(value is DBNull ? default(uint) : value);
            }
            if (memberType == typeof(short))
            {
                return(value is DBNull ? default(short) : value);
            }
            if (memberType == typeof(ushort))
            {
                return(value is DBNull ? default(ushort) : value);
            }
            if (memberType == typeof(long))
            {
                return(value is DBNull ? default(long) : value);
            }
            if (memberType == typeof(ulong))
            {
                return(value is DBNull ? default(ulong) : value);
            }
            if (memberType == typeof(byte))
            {
                return(value is DBNull ? default(byte) : value);
            }
            if (memberType == typeof(sbyte))
            {
                return(value is DBNull ? default(sbyte) : value);
            }
            if (memberType == typeof(bool))
            {
                return(value is DBNull ? default(bool) : value);
            }
            if (memberType == typeof(float))
            {
                return(value is DBNull ? default(float) : value);
            }
            if (memberType == typeof(double))
            {
                return(value is DBNull ? default(double) : value);
            }
            if (memberType == typeof(decimal))
            {
                return(value is DBNull ? default(decimal) : value);
            }
            if (memberType == typeof(char))
            {
                return(value is DBNull ? default(char) : value);
            }
            if (memberType == typeof(string))
            {
                return(value is DBNull ? default(string) : value);
            }
            if (memberType == typeof(Guid))
            {
                return(value is DBNull ? default(Guid) : value);
            }
            if (memberType == typeof(DateTime))
            {
                return(value is DBNull ? default(DateTime) : value);
            }
            if (memberType == typeof(DateTimeOffset))
            {
                return(value is DBNull ? default(DateTimeOffset) : value);
            }
            if (memberType == typeof(byte[]))
            {
                return(value);
            }

            if (memberType == typeof(int?))
            {
                return(value is DBNull ? default(int?) : value);
            }
            if (memberType == typeof(uint?))
            {
                return(value is DBNull ? default(uint?) : value);
            }
            if (memberType == typeof(short?))
            {
                return(value is DBNull ? default(short?) : value);
            }
            if (memberType == typeof(ushort?))
            {
                return(value is DBNull ? default(ushort?) : value);
            }
            if (memberType == typeof(long?))
            {
                return(value is DBNull ? default(long?) : value);
            }
            if (memberType == typeof(ulong?))
            {
                return(value is DBNull ? default(ulong?) : value);
            }
            if (memberType == typeof(byte?))
            {
                return(value is DBNull ? default(byte?) : value);
            }
            if (memberType == typeof(sbyte?))
            {
                return(value is DBNull ? default(sbyte?) : value);
            }
            if (memberType == typeof(bool?))
            {
                return(value is DBNull ? default(bool?) : value);
            }
            if (memberType == typeof(float?))
            {
                return(value is DBNull ? default(float?) : value);
            }
            if (memberType == typeof(double?))
            {
                return(value is DBNull ? default(double?) : value);
            }
            if (memberType == typeof(decimal?))
            {
                return(value is DBNull ? default(decimal?) : value);
            }
            if (memberType == typeof(char?))
            {
                return(value is DBNull ? default(char?) : value);
            }
            if (memberType == typeof(Guid?))
            {
                return(value is DBNull ? default(Guid?) : value);
            }
            if (memberType == typeof(DateTime?))
            {
                return(value is DBNull ? default(DateTime?) : value);
            }
            if (memberType == typeof(DateTimeOffset?))
            {
                return(value is DBNull ? default(DateTimeOffset?) : value);
            }

            if (memberType == typeof(FSharpOption <int>))
            {
                return(value is DBNull ? FSharpOption <int> .None : FSharpOption <int> .Some((int)value));
            }
            if (memberType == typeof(FSharpOption <uint>))
            {
                return(value is DBNull ? FSharpOption <uint> .None : FSharpOption <uint> .Some((uint)value));
            }
            if (memberType == typeof(FSharpOption <short>))
            {
                return(value is DBNull ? FSharpOption <short> .None : FSharpOption <short> .Some((short)value));
            }
            if (memberType == typeof(FSharpOption <ushort>))
            {
                return(value is DBNull ? FSharpOption <ushort> .None : FSharpOption <ushort> .Some((ushort)value));
            }
            if (memberType == typeof(FSharpOption <long>))
            {
                return(value is DBNull ? FSharpOption <long> .None : FSharpOption <long> .Some((long)value));
            }
            if (memberType == typeof(FSharpOption <ulong>))
            {
                return(value is DBNull ? FSharpOption <ulong> .None : FSharpOption <ulong> .Some((ulong)value));
            }
            if (memberType == typeof(FSharpOption <byte>))
            {
                return(value is DBNull ? FSharpOption <byte> .None : FSharpOption <byte> .Some((byte)value));
            }
            if (memberType == typeof(FSharpOption <sbyte>))
            {
                return(value is DBNull ? FSharpOption <sbyte> .None : FSharpOption <sbyte> .Some((sbyte)value));
            }
            if (memberType == typeof(FSharpOption <bool>))
            {
                return(value is DBNull ? FSharpOption <bool> .None : FSharpOption <bool> .Some((bool)value));
            }
            if (memberType == typeof(FSharpOption <float>))
            {
                return(value is DBNull ? FSharpOption <float> .None : FSharpOption <float> .Some((float)value));
            }
            if (memberType == typeof(FSharpOption <double>))
            {
                return(value is DBNull ? FSharpOption <double> .None : FSharpOption <double> .Some((double)value));
            }
            if (memberType == typeof(FSharpOption <decimal>))
            {
                return(value is DBNull ? FSharpOption <decimal> .None : FSharpOption <decimal> .Some((decimal)value));
            }
            if (memberType == typeof(FSharpOption <char>))
            {
                return(value is DBNull ? FSharpOption <char> .None : FSharpOption <char> .Some((char)value));
            }
            if (memberType == typeof(FSharpOption <string>))
            {
                return(value is DBNull ? FSharpOption <string> .None : FSharpOption <string> .Some((string)value));
            }
            if (memberType == typeof(FSharpOption <Guid>))
            {
                return(value is DBNull ? FSharpOption <Guid> .None : FSharpOption <Guid> .Some((Guid)value));
            }
            if (memberType == typeof(FSharpOption <DateTime>))
            {
                return(value is DBNull ? FSharpOption <DateTime> .None : FSharpOption <DateTime> .Some((DateTime)value));
            }
            if (memberType == typeof(FSharpOption <DateTimeOffset>))
            {
                return(value is DBNull ? FSharpOption <DateTimeOffset> .None : FSharpOption <DateTimeOffset> .Some((DateTimeOffset)value));
            }
            if (memberType == typeof(FSharpOption <byte[]>))
            {
                return(value is DBNull ? FSharpOption <byte[]> .None : FSharpOption <byte[]> .Some((byte[])value));
            }

            // optional values (F#)
            if (memberType.IsGenericType &&
                !memberType.IsGenericTypeDefinition &&
                !memberType.IsGenericParameter &&
                typeof(FSharpOption <>) == memberType.GetGenericTypeDefinition())
            {
                if (value is DBNull)
                {
                    return(memberType.GetProperty("None", BindingFlags.Public | BindingFlags.Static).GetGetMethod().Invoke(null, null));
                }

                var genericTypes = memberType.GetGenericArguments();
                if (genericTypes.Length != 1)
                {
                    throw new Exception("Invalid fsharp option value.");
                }

                var genericType = genericTypes[0];
                return(memberType.GetMethod("Some", BindingFlags.Public | BindingFlags.Static).Invoke(null, new object[] { Resolve(genericType, value) }));
            }

            // discriminated unions (F#)
            if (FSharpType.IsUnion(memberType, none))
            {
                var ctor = FSharpType.GetUnionCases(memberType, none).FirstOrDefault(cinfo => cinfo.GetFields().Length == 1);
                if (ctor == null)
                {
                    throw new Exception("Invalid discriminated-unions.");
                }

                var field = ctor.GetFields()[0];
                return(FSharpValue.MakeUnion(ctor, new object[] { Resolve(field.PropertyType, value) }, none));
            }

            // nullable values
            if (memberType.IsGenericType &&
                !memberType.IsGenericTypeDefinition &&
                !memberType.IsGenericParameter &&
                typeof(Nullable <>) == memberType.GetGenericTypeDefinition())
            {
                return(value is DBNull ? null : value);
            }

            // non nullable values
            if (memberType.IsValueType)
            {
                return(value is DBNull?Activator.CreateInstance(memberType) : value);
            }

            // class values
            if (memberType.IsClass)
            {
                if (value is string)
                {
                    return(value);
                }

                return(value is DBNull ? null : Activator.CreateInstance(memberType, value));
            }

            // enums
            if (memberType.IsEnum)
            {
                if (value is DBNull)
                {
                    return(memberType.GetEnumValue(0));
                }

                if (value is short s)
                {
                    return(memberType.GetEnumValue(s));
                }
                if (value is int i)
                {
                    return(memberType.GetEnumValue(i));
                }
                if (value is long l)
                {
                    return(memberType.GetEnumValue(l));
                }

                if (value is ushort us)
                {
                    return(memberType.GetEnumValue(us));
                }
                if (value is uint ui)
                {
                    return(memberType.GetEnumValue(ui));
                }
                if (value is ulong ul)
                {
                    return(memberType.GetEnumValue(ul));
                }

                if (value is byte b)
                {
                    return(memberType.GetEnumValue(b));
                }
                if (value is sbyte sb)
                {
                    return(memberType.GetEnumValue(sb));
                }
            }

            throw new Exception("Could not resolve the value.");
        }