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()); }
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); }
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()); }
/// <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."); }