Created
March 12, 2018 08:30
-
-
Save DerekZiemba/468b84d7b5a5a289470859e261f17217 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.ComponentModel; | |
using System.Globalization; | |
using System.Linq; | |
using System.Reflection; | |
using System.Reflection.Emit; | |
namespace ExampleILGeneratorShallowCopy { | |
class ExampleILGeneratorShallowCopy { | |
static void Main(string[] args) { | |
DBLocation dbloc = new DBLocation(){ | |
Name="Microsoft", | |
AddressLine ="1 Microsoft Way", | |
Locality="Redmond", | |
AdminDistrict="Washington", | |
PostalCode="98052", | |
CountryRegion="USA", | |
Latitude=47.6740, | |
Longitude=122.1215 | |
}; | |
StreetAddress apiloc = new StreetAddress(); | |
RuntimeCompiler.CopyIntoDelegate<StreetAddress, DBLocation> copier = RuntimeCompiler.CompileShallowPropertyCopier<StreetAddress, DBLocation>(); | |
copier(apiloc, dbloc); | |
Console.WriteLine(apiloc.ToString()); | |
Console.WriteLine(apiloc.Latitude); | |
Console.WriteLine(apiloc.Longitude); | |
} | |
public static void CopyExample(StreetAddress target, DBLocation src) { | |
target.Locality = src.Locality; | |
target.Latitude = (float)TypeConversion.Float32Converter.ConvertFrom(src.Latitude); | |
} | |
//Generates the following: | |
//.method public hidebysig static void | |
// CopyExample( | |
// class ExampleILGeneratorShallowCopy.StreetAddress target, | |
// class ExampleILGeneratorShallowCopy.DBLocation src | |
// ) cil managed | |
//{ | |
// .maxstack 8 | |
// // [36 4 - 36 35] | |
// IL_0000: ldarg.0 // target | |
// IL_0001: ldarg.1 // src | |
// IL_0002: callvirt instance string ExampleILGeneratorShallowCopy.DBLocation::get_Locality() | |
// IL_0007: callvirt instance void ExampleILGeneratorShallowCopy.StreetAddress::set_Locality(string) | |
// // [37 4 - 37 87] | |
// IL_000c: ldarg.0 // target | |
// IL_000d: ldsfld class [System.ComponentModel.TypeConverter]System.ComponentModel.SingleConverter ExampleILGeneratorShallowCopy.TypeConversion::Float32Converter | |
// IL_0012: ldarg.1 // src | |
// IL_0013: callvirt instance float64 ExampleILGeneratorShallowCopy.DBLocation::get_Latitude() | |
// IL_0018: box [System.Runtime]System.Double | |
// IL_001d: callvirt instance object [System.ComponentModel.TypeConverter]System.ComponentModel.TypeConverter::ConvertFrom(object) | |
// IL_0022: unbox.any [System.Runtime]System.Single | |
// IL_0027: callvirt instance void ExampleILGeneratorShallowCopy.StreetAddress::set_Latitude(float32) | |
// // [38 3 - 38 4] | |
// IL_002c: ret | |
//} // end of method ExampleILGeneratorShallowCopy::CopyExample | |
} | |
public static class Common { | |
public static T UnBox<T>(this T? input, T @default = default(T)) where T : struct => input ?? @default; | |
public static bool EqIgCase(this string str, string other) => String.Equals(str, other, StringComparison.OrdinalIgnoreCase); | |
public static string ToStringJoin(this IEnumerable<string> ienum, string separator = ", ") => String.Join(separator, from string x in ienum where !string.IsNullOrWhiteSpace(x) select x.Trim()); | |
public static bool IsNullable(this Type type) => type.IsGenericType && !type.IsGenericTypeDefinition && type.GetGenericTypeDefinition() == typeof(Nullable<>); | |
public static TValue GetItemOrDefault<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key, TValue @default = default(TValue)) { | |
TValue value; | |
return dict.TryGetValue(key, out value) ? value : @default; | |
} | |
} | |
public static class RuntimeCompiler { | |
public delegate void CopyIntoDelegate<T, S>(T location, S src); | |
private static class RCCache_Copiers<T, S> { | |
public static object Lock = new object(); | |
public static CopyIntoDelegate<T, S> ShallowPropertyCopier; | |
} | |
public static CopyIntoDelegate<T, S> CompileShallowPropertyCopier<T, S>() { | |
if (RCCache_Copiers<T, S>.ShallowPropertyCopier is null) { | |
lock (RCCache_Copiers<T, S>.Lock) { | |
if (RCCache_Copiers<T, S>.ShallowPropertyCopier != null) { | |
return RCCache_Copiers<T, S>.ShallowPropertyCopier; | |
} | |
Type targetType = typeof(T); | |
Type srcType = typeof(S); | |
BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; | |
PropertyInfo[] targetProps = targetType.GetProperties(flags); | |
PropertyInfo[] srcProps = targetType == srcType ? targetProps : srcType.GetProperties(flags); | |
DynamicMethod dynmethod = new DynamicMethod("ShallowPropCopy", typeof(void), new Type[2]{ targetType, srcType }, true); | |
ILGenerator gen = dynmethod.GetILGenerator(); | |
foreach (PropertyInfo targetProp in targetProps) { | |
if (!targetProp.CanWrite) { continue; } | |
PropertyInfo srcProp = targetType == srcType ? targetProp : srcProps.FirstOrDefault(f=>f.Name.EqIgCase(targetProp.Name)); | |
if (srcProp is null || !srcProp.CanRead) { continue; } | |
if (targetProp.PropertyType == srcProp.PropertyType) { | |
gen.Emit(OpCodes.Ldarg_0); | |
gen.Emit(OpCodes.Ldarg_1); | |
gen.Emit(OpCodes.Callvirt, srcProp.GetMethod); | |
gen.Emit(OpCodes.Callvirt, targetProp.SetMethod); | |
} else { | |
TypeConverter converter = TypeConversion.TypeConverterLookup.GetItemOrDefault(targetProp.PropertyType); | |
FieldInfo converterField = GetStaticConverterFieldByConverter(converter); | |
if (converterField != null && converter.CanConvertFrom(srcProp.PropertyType)) { | |
MethodInfo convertFrom = converter.GetType().GetMethod(nameof(TypeConverter.ConvertFrom), new Type[] { typeof(object) }); | |
gen.Emit(OpCodes.Ldarg_0); | |
gen.Emit(OpCodes.Ldsfld, converterField); | |
gen.Emit(OpCodes.Ldarg_1); | |
gen.Emit(OpCodes.Callvirt, srcProp.GetMethod); | |
gen.Emit(OpCodes.Box, srcProp.PropertyType); | |
gen.Emit(OpCodes.Callvirt, convertFrom); | |
gen.Emit(OpCodes.Unbox_Any); | |
gen.Emit(OpCodes.Callvirt, targetProp.SetMethod); | |
} | |
} | |
} | |
gen.Emit(OpCodes.Ret); | |
RCCache_Copiers<T, S>.ShallowPropertyCopier = (CopyIntoDelegate<T, S>)dynmethod.CreateDelegate(typeof(CopyIntoDelegate<T, S>)); | |
} | |
} | |
return RCCache_Copiers<T, S>.ShallowPropertyCopier; | |
} | |
private static FieldInfo GetStaticConverterFieldByConverter(TypeConverter converter) { | |
Type type = typeof(TypeConversion); | |
if (converter == TypeConversion.StringConverter) { return type.GetField(nameof(TypeConversion.StringConverter)); } | |
if (converter == TypeConversion.CharConverter) { return type.GetField(nameof(TypeConversion.CharConverter)); } | |
if (converter == TypeConversion.BoolConverter) { return type.GetField(nameof(TypeConversion.BoolConverter)); } | |
if (converter == TypeConversion.SByteConverter) { return type.GetField(nameof(TypeConversion.SByteConverter)); } | |
if (converter == TypeConversion.Int16Converter) { return type.GetField(nameof(TypeConversion.Int16Converter)); } | |
if (converter == TypeConversion.Int32Converter) { return type.GetField(nameof(TypeConversion.Int32Converter)); } | |
if (converter == TypeConversion.Int64Converter) { return type.GetField(nameof(TypeConversion.Int64Converter)); } | |
if (converter == TypeConversion.ByteConverter) { return type.GetField(nameof(TypeConversion.ByteConverter)); } | |
if (converter == TypeConversion.UInt16Converter) { return type.GetField(nameof(TypeConversion.UInt16Converter)); } | |
if (converter == TypeConversion.UInt32Converter) { return type.GetField(nameof(TypeConversion.UInt32Converter)); } | |
if (converter == TypeConversion.UInt64Converter) { return type.GetField(nameof(TypeConversion.UInt64Converter)); } | |
if (converter == TypeConversion.Float32Converter) { return type.GetField(nameof(TypeConversion.Float32Converter)); } | |
if (converter == TypeConversion.Float64Converter) { return type.GetField(nameof(TypeConversion.Float64Converter)); } | |
if (converter == TypeConversion.DecimalConverter) { return type.GetField(nameof(TypeConversion.DecimalConverter)); } | |
if (converter == TypeConversion.DateTimeConverter) { return type.GetField(nameof(TypeConversion.DateTimeConverter)); } | |
if (converter == TypeConversion.TimeSpanConverter) { return type.GetField(nameof(TypeConversion.TimeSpanConverter)); } | |
if (converter == TypeConversion.GuidConverter) { return type.GetField(nameof(TypeConversion.GuidConverter)); } | |
return null; | |
} | |
} | |
public class StreetAddress { | |
private string _name; | |
private string _addressLine; | |
private string _locality; //city | |
private string _adminDistrict; //state | |
private string _postalCode; | |
private string _countryRegion; | |
private string _description; | |
private float _latitude; | |
private float _longitude; | |
public string Name { get => _name; set => _name = value; } | |
public string AddressLine { get => _addressLine; set => _addressLine = value; } | |
public string Locality { get => _locality; set => _locality = value; } | |
public string AdminDistrict { get => _adminDistrict; set => _adminDistrict = value; } | |
public string PostalCode { get => _postalCode; set => _postalCode = value; } | |
public string CountryRegion { get => _countryRegion; set => _countryRegion = value; } | |
public string Description { get => _description; set => _description = value; } | |
public float Latitude { get => _latitude; set => _latitude = value; } | |
public float Longitude { get => _longitude; set => _longitude = value; } | |
public StreetAddress() { } | |
public override string ToString() => FormatAddress(Name, AddressLine, Locality, AdminDistrict, PostalCode, CountryRegion); | |
public static string FormatAddress(string sName, string sAddressline, string sCity, string sState, string sZip, string sCountry, string lineSeparator = ", \n") { | |
//This is a non performant call because ToStringJoin uses LINQ. But so much easier than alternatives. | |
return new string[] { sName, | |
sAddressline, | |
new string[] { sCity, | |
new string[] { sState, sZip }.ToStringJoin(" "), | |
sCountry }.ToStringJoin(", "), | |
}.ToStringJoin(lineSeparator); | |
} | |
} | |
public class DBLocation { | |
private Int64 _LocationID; | |
private Int64? _ParentLocationID; | |
private string _Name; | |
private string _AddressLine; | |
private string _Locality; //city | |
private string _AdminDistrict; //state | |
private string _PostalCode; | |
private string _CountryRegion; | |
private int? _Latitude6x; | |
private int? _Longitude6x; | |
private string _Description; | |
public DBLocation() { } | |
public Int64 LocationID { get => _LocationID; set => _LocationID = value; } | |
public Int64? ParentLocationID { get => _ParentLocationID; set => _ParentLocationID = value; } | |
public string Name { get => _Name; set => _Name = value; } | |
public string AddressLine { get => _AddressLine; set => _AddressLine = value; } | |
public string Locality { get => _Locality; set => _Locality = value; } | |
public string AdminDistrict { get => _AdminDistrict; set => _AdminDistrict = value; } | |
public string PostalCode { get => _PostalCode; set => _PostalCode = value; } | |
public string CountryRegion { get => _CountryRegion; set => _CountryRegion = value; } | |
public int? Latitude6x { get => _Latitude6x; set => _Latitude6x = value; } | |
public int? Longitude6x { get => _Longitude6x; set => _Longitude6x = value; } | |
public string Description { get => _Description; set => _Description = value; } | |
public double Latitude { get => _Latitude6x.UnBox() / 10e6; set => _Latitude6x = (int)(value * 10e6); } | |
public double Longitude { get => _Longitude6x.UnBox() / 10e6; set => _Longitude6x = (int)(value * 10e6); } | |
} | |
public static class TypeConversion { | |
private static IFormatProvider defaultProvider = System.Threading.Thread.CurrentThread.CurrentCulture; | |
public static readonly StringConverter StringConverter = new StringConverter(); | |
public static readonly BooleanConverter BoolConverter = new MyBooleanConverter(); | |
public static readonly CharConverter CharConverter = new MyCharConverter(); | |
public static readonly SByteConverter SByteConverter = new MySByteConverter(); | |
public static readonly Int16Converter Int16Converter = new MyInt16Converter(); | |
public static readonly Int32Converter Int32Converter = new MyInt32Converter(); | |
public static readonly Int64Converter Int64Converter = new MyInt64Converter(); | |
public static readonly ByteConverter ByteConverter = new MyByteConverter(); | |
public static readonly UInt16Converter UInt16Converter = new MyUInt16Converter(); | |
public static readonly UInt32Converter UInt32Converter = new MyUInt32Converter(); | |
public static readonly UInt64Converter UInt64Converter = new MyUInt64Converter(); | |
public static readonly SingleConverter Float32Converter = new MyFloat32Converter(); | |
public static readonly DoubleConverter Float64Converter = new MyFloat64Converter(); | |
public static readonly DecimalConverter DecimalConverter = new MyDecimalConverter(); | |
public static readonly DateTimeConverter DateTimeConverter = new MyDateTimeConverter(); | |
public static readonly TimeSpanConverter TimeSpanConverter = new TimeSpanConverter(); | |
public static readonly GuidConverter GuidConverter = new GuidConverter(); | |
public static readonly Dictionary<Type, TypeConverter> TypeConverterLookup =((Func<Dictionary<Type, TypeConverter>>)( | |
() => { | |
var dict = new Dictionary<Type, TypeConverter>(40); | |
dict[typeof(string)]=StringConverter; | |
dict[typeof(bool)]=BoolConverter; | |
dict[typeof(char)]=CharConverter; | |
dict[typeof(sbyte)]=SByteConverter; | |
dict[typeof(Int16)]=Int16Converter; | |
dict[typeof(Int32)]=Int32Converter; | |
dict[typeof(Int64)]=Int64Converter; | |
dict[typeof(byte)]=ByteConverter; | |
dict[typeof(UInt16)]=UInt16Converter; | |
dict[typeof(UInt32)]=UInt32Converter; | |
dict[typeof(UInt64)]=UInt64Converter; | |
dict[typeof(Single)]=Float32Converter; | |
dict[typeof(Double)]=Float64Converter; | |
dict[typeof(Decimal)]=DecimalConverter; | |
dict[typeof(DateTime)]=DateTimeConverter; | |
dict[typeof(TimeSpan)]=TimeSpanConverter; | |
dict[typeof(Guid)]=GuidConverter; | |
dict[typeof(bool?)]=BoolConverter; | |
dict[typeof(char?)]=CharConverter; | |
dict[typeof(sbyte?)]=SByteConverter; | |
dict[typeof(Int16?)]=Int16Converter; | |
dict[typeof(Int32?)]=Int32Converter; | |
dict[typeof(Int64?)]=Int64Converter; | |
dict[typeof(byte?)]=ByteConverter; | |
dict[typeof(UInt16?)]=UInt16Converter; | |
dict[typeof(UInt32?)]=UInt32Converter; | |
dict[typeof(UInt64?)]=UInt64Converter; | |
dict[typeof(Single?)]=Float32Converter; | |
dict[typeof(Double?)]=Float64Converter; | |
dict[typeof(Decimal?)]=DecimalConverter; | |
dict[typeof(DateTime?)]=DateTimeConverter; | |
dict[typeof(TimeSpan?)]=TimeSpanConverter; | |
dict[typeof(Guid?)]=GuidConverter; | |
return dict; | |
}))(); | |
private class MyBooleanConverter : BooleanConverter { | |
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) => base.CanConvertFrom(context, sourceType) || typeof(IConvertible).IsAssignableFrom(sourceType); | |
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { | |
if (value is null) { return base.ConvertFrom(context, culture, value); } | |
Type fromType = value.GetType(); | |
if (fromType.IsNullable()) { fromType = fromType.GetGenericArguments()[0]; } | |
TypeCode fromTypeCode = Type.GetTypeCode(fromType); | |
switch (fromTypeCode) { | |
case TypeCode.Boolean: | |
return (Boolean)value; | |
case TypeCode.Char: | |
switch ((char)value) { | |
case '1': | |
case 'T': | |
case 't': | |
case 'Y': | |
case 'y': | |
return true; | |
case '0': | |
case 'F': | |
case 'f': | |
case 'N': | |
case 'n': | |
return false; | |
} | |
return null; | |
case TypeCode.SByte: return ((SByte)value) != 0; | |
case TypeCode.Int16: return ((Int16)value) != 0; | |
case TypeCode.Int32: return ((Int32)value) != 0; | |
case TypeCode.Int64: return ((Int64)value) != 0; | |
case TypeCode.Byte: return ((Byte)value) != 0; | |
case TypeCode.UInt16: return ((UInt16)value) != 0; | |
case TypeCode.UInt32: return ((UInt32)value) != 0; | |
case TypeCode.UInt64: return ((UInt64)value) != 0; | |
case TypeCode.Single: return ((Single)value) != 0; | |
case TypeCode.Double: return ((Double)value) != 0; | |
case TypeCode.Decimal: return ((Decimal)value) != 0; | |
case TypeCode.DateTime: return ((DateTime)value) > DateTime.MinValue && ((DateTime)value) < DateTime.MaxValue; | |
default: return base.ConvertFrom(context, culture, value); | |
} | |
} | |
} | |
private class MyCharConverter : CharConverter { | |
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) => base.CanConvertFrom(context, sourceType) || typeof(IConvertible).IsAssignableFrom(sourceType); | |
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { | |
if (value is null) { return base.ConvertFrom(context, culture, value); } | |
Type fromType = value.GetType(); | |
if (fromType.IsNullable()) { fromType = fromType.GetGenericArguments()[0]; } | |
TypeCode fromTypeCode = Type.GetTypeCode(fromType); | |
IConvertible convertible = value as IConvertible; | |
switch (fromTypeCode) { | |
case TypeCode.Boolean: return (Boolean)value ? '1' : '0'; | |
case TypeCode.Char: return (Char)value; | |
case TypeCode.SByte: | |
case TypeCode.Int16: | |
case TypeCode.Int32: | |
case TypeCode.Int64: | |
case TypeCode.Byte: | |
case TypeCode.UInt16: | |
case TypeCode.UInt32: | |
case TypeCode.UInt64: | |
case TypeCode.Single: | |
case TypeCode.Double: | |
case TypeCode.Decimal: | |
case TypeCode.DateTime: | |
return convertible.ToChar(defaultProvider); | |
default: return base.ConvertFrom(context, culture, value); | |
} | |
} | |
} | |
private class MySByteConverter : SByteConverter { | |
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) => base.CanConvertFrom(context, sourceType) || typeof(IConvertible).IsAssignableFrom(sourceType); | |
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { | |
if (value is null) { return base.ConvertFrom(context, culture, value); } | |
Type fromType = value.GetType(); | |
if (fromType.IsNullable()) { fromType = fromType.GetGenericArguments()[0]; } | |
TypeCode fromTypeCode = Type.GetTypeCode(fromType); | |
IConvertible convertible = value as IConvertible; | |
switch (fromTypeCode) { | |
case TypeCode.Boolean: return (Boolean)value ? '1' : '0'; | |
case TypeCode.Char: | |
case TypeCode.SByte: | |
case TypeCode.Int16: | |
case TypeCode.Int32: | |
case TypeCode.Int64: | |
case TypeCode.Byte: | |
case TypeCode.UInt16: | |
case TypeCode.UInt32: | |
case TypeCode.UInt64: | |
case TypeCode.Single: | |
case TypeCode.Double: | |
case TypeCode.Decimal: | |
case TypeCode.DateTime: | |
return convertible.ToSByte(defaultProvider); | |
default: return base.ConvertFrom(context, culture, value); | |
} | |
} | |
} | |
private class MyInt16Converter : Int16Converter { | |
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) => base.CanConvertFrom(context, sourceType) || typeof(IConvertible).IsAssignableFrom(sourceType); | |
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { | |
if (value is null) { return base.ConvertFrom(context, culture, value); } | |
Type fromType = value.GetType(); | |
if (fromType.IsNullable()) { fromType = fromType.GetGenericArguments()[0]; } | |
TypeCode fromTypeCode = Type.GetTypeCode(fromType); | |
IConvertible convertible = value as IConvertible; | |
switch (fromTypeCode) { | |
case TypeCode.Boolean: return (Boolean)value ? '1' : '0'; | |
case TypeCode.Char: | |
case TypeCode.SByte: | |
case TypeCode.Int16: | |
case TypeCode.Int32: | |
case TypeCode.Int64: | |
case TypeCode.Byte: | |
case TypeCode.UInt16: | |
case TypeCode.UInt32: | |
case TypeCode.UInt64: | |
case TypeCode.Single: | |
case TypeCode.Double: | |
case TypeCode.Decimal: | |
case TypeCode.DateTime: | |
return convertible.ToInt16(defaultProvider); | |
default: return base.ConvertFrom(context, culture, value); | |
} | |
} | |
} | |
private class MyInt32Converter : Int32Converter { | |
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) => base.CanConvertFrom(context, sourceType) || typeof(IConvertible).IsAssignableFrom(sourceType); | |
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { | |
if (value is null) { return base.ConvertFrom(context, culture, value); } | |
Type fromType = value.GetType(); | |
if (fromType.IsNullable()) { fromType = fromType.GetGenericArguments()[0]; } | |
TypeCode fromTypeCode = Type.GetTypeCode(fromType); | |
IConvertible convertible = value as IConvertible; | |
switch (fromTypeCode) { | |
case TypeCode.Boolean: return (Boolean)value ? '1' : '0'; | |
case TypeCode.Char: | |
case TypeCode.SByte: | |
case TypeCode.Int16: | |
case TypeCode.Int32: | |
case TypeCode.Int64: | |
case TypeCode.Byte: | |
case TypeCode.UInt16: | |
case TypeCode.UInt32: | |
case TypeCode.UInt64: | |
case TypeCode.Single: | |
case TypeCode.Double: | |
case TypeCode.Decimal: | |
case TypeCode.DateTime: | |
return convertible.ToInt32(defaultProvider); | |
default: return base.ConvertFrom(context, culture, value); | |
} | |
} | |
} | |
private class MyInt64Converter : Int64Converter { | |
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) => base.CanConvertFrom(context, sourceType) || typeof(IConvertible).IsAssignableFrom(sourceType); | |
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { | |
if (value is null) { return base.ConvertFrom(context, culture, value); } | |
Type fromType = value.GetType(); | |
if (fromType.IsNullable()) { fromType = fromType.GetGenericArguments()[0]; } | |
TypeCode fromTypeCode = Type.GetTypeCode(fromType); | |
IConvertible convertible = value as IConvertible; | |
switch (fromTypeCode) { | |
case TypeCode.Boolean: return (Boolean)value ? '1' : '0'; | |
case TypeCode.Char: | |
case TypeCode.SByte: | |
case TypeCode.Int16: | |
case TypeCode.Int32: | |
case TypeCode.Int64: | |
case TypeCode.Byte: | |
case TypeCode.UInt16: | |
case TypeCode.UInt32: | |
case TypeCode.UInt64: | |
case TypeCode.Single: | |
case TypeCode.Double: | |
case TypeCode.Decimal: | |
case TypeCode.DateTime: | |
return convertible.ToInt64(defaultProvider); | |
default: return base.ConvertFrom(context, culture, value); | |
} | |
} | |
} | |
private class MyByteConverter : ByteConverter { | |
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) => base.CanConvertFrom(context, sourceType) || typeof(IConvertible).IsAssignableFrom(sourceType); | |
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { | |
if (value is null) { return base.ConvertFrom(context, culture, value); } | |
Type fromType = value.GetType(); | |
if (fromType.IsNullable()) { fromType = fromType.GetGenericArguments()[0]; } | |
TypeCode fromTypeCode = Type.GetTypeCode(fromType); | |
IConvertible convertible = value as IConvertible; | |
switch (fromTypeCode) { | |
case TypeCode.Boolean: return (Boolean)value ? '1' : '0'; | |
case TypeCode.Char: | |
case TypeCode.SByte: | |
case TypeCode.Int16: | |
case TypeCode.Int32: | |
case TypeCode.Int64: | |
case TypeCode.Byte: | |
case TypeCode.UInt16: | |
case TypeCode.UInt32: | |
case TypeCode.UInt64: | |
case TypeCode.Single: | |
case TypeCode.Double: | |
case TypeCode.Decimal: | |
case TypeCode.DateTime: | |
return convertible.ToByte(defaultProvider); | |
default: return base.ConvertFrom(context, culture, value); | |
} | |
} | |
} | |
private class MyUInt16Converter : UInt16Converter { | |
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) => base.CanConvertFrom(context, sourceType) || typeof(IConvertible).IsAssignableFrom(sourceType); | |
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { | |
if (value is null) { return base.ConvertFrom(context, culture, value); } | |
Type fromType = value.GetType(); | |
if (fromType.IsNullable()) { fromType = fromType.GetGenericArguments()[0]; } | |
TypeCode fromTypeCode = Type.GetTypeCode(fromType); | |
IConvertible convertible = value as IConvertible; | |
switch (fromTypeCode) { | |
case TypeCode.Boolean: return (Boolean)value ? '1' : '0'; | |
case TypeCode.Char: | |
case TypeCode.SByte: | |
case TypeCode.Int16: | |
case TypeCode.Int32: | |
case TypeCode.Int64: | |
case TypeCode.Byte: | |
case TypeCode.UInt16: | |
case TypeCode.UInt32: | |
case TypeCode.UInt64: | |
case TypeCode.Single: | |
case TypeCode.Double: | |
case TypeCode.Decimal: | |
case TypeCode.DateTime: | |
return convertible.ToUInt16(defaultProvider); | |
default: return base.ConvertFrom(context, culture, value); | |
} | |
} | |
} | |
private class MyUInt32Converter : UInt32Converter { | |
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) => base.CanConvertFrom(context, sourceType) || typeof(IConvertible).IsAssignableFrom(sourceType); | |
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { | |
if (value is null) { return base.ConvertFrom(context, culture, value); } | |
Type fromType = value.GetType(); | |
if (fromType.IsNullable()) { fromType = fromType.GetGenericArguments()[0]; } | |
TypeCode fromTypeCode = Type.GetTypeCode(fromType); | |
IConvertible convertible = value as IConvertible; | |
switch (fromTypeCode) { | |
case TypeCode.Boolean: return (Boolean)value ? '1' : '0'; | |
case TypeCode.Char: | |
case TypeCode.SByte: | |
case TypeCode.Int16: | |
case TypeCode.Int32: | |
case TypeCode.Int64: | |
case TypeCode.Byte: | |
case TypeCode.UInt16: | |
case TypeCode.UInt32: | |
case TypeCode.UInt64: | |
case TypeCode.Single: | |
case TypeCode.Double: | |
case TypeCode.Decimal: | |
case TypeCode.DateTime: | |
return convertible.ToUInt32(defaultProvider); | |
default: return base.ConvertFrom(context, culture, value); | |
} | |
} | |
} | |
private class MyUInt64Converter : UInt64Converter { | |
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) => base.CanConvertFrom(context, sourceType) || typeof(IConvertible).IsAssignableFrom(sourceType); | |
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { | |
if (value is null) { return base.ConvertFrom(context, culture, value); } | |
Type fromType = value.GetType(); | |
if (fromType.IsNullable()) { fromType = fromType.GetGenericArguments()[0]; } | |
TypeCode fromTypeCode = Type.GetTypeCode(fromType); | |
IConvertible convertible = value as IConvertible; | |
switch (fromTypeCode) { | |
case TypeCode.Boolean: return (Boolean)value ? '1' : '0'; | |
case TypeCode.Char: | |
case TypeCode.SByte: | |
case TypeCode.Int16: | |
case TypeCode.Int32: | |
case TypeCode.Int64: | |
case TypeCode.Byte: | |
case TypeCode.UInt16: | |
case TypeCode.UInt32: | |
case TypeCode.UInt64: | |
case TypeCode.Single: | |
case TypeCode.Double: | |
case TypeCode.Decimal: | |
case TypeCode.DateTime: | |
return convertible.ToUInt64(defaultProvider); | |
default: return base.ConvertFrom(context, culture, value); | |
} | |
} | |
} | |
private class MyFloat32Converter : SingleConverter { | |
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) => base.CanConvertFrom(context, sourceType) || typeof(IConvertible).IsAssignableFrom(sourceType); | |
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { | |
if (value is null) { return base.ConvertFrom(context, culture, value); } | |
Type fromType = value.GetType(); | |
if (fromType.IsNullable()) { fromType = fromType.GetGenericArguments()[0]; } | |
TypeCode fromTypeCode = Type.GetTypeCode(fromType); | |
IConvertible convertible = value as IConvertible; | |
switch (fromTypeCode) { | |
case TypeCode.Boolean: return (Boolean)value ? '1' : '0'; | |
case TypeCode.Char: | |
case TypeCode.SByte: | |
case TypeCode.Int16: | |
case TypeCode.Int32: | |
case TypeCode.Int64: | |
case TypeCode.Byte: | |
case TypeCode.UInt16: | |
case TypeCode.UInt32: | |
case TypeCode.UInt64: | |
case TypeCode.Single: | |
case TypeCode.Double: | |
case TypeCode.Decimal: | |
case TypeCode.DateTime: | |
return convertible.ToSingle(defaultProvider); | |
default: return base.ConvertFrom(context, culture, value); | |
} | |
} | |
} | |
private class MyFloat64Converter : DoubleConverter { | |
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) => base.CanConvertFrom(context, sourceType) || typeof(IConvertible).IsAssignableFrom(sourceType); | |
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { | |
if (value is null) { return base.ConvertFrom(context, culture, value); } | |
Type fromType = value.GetType(); | |
if (fromType.IsNullable()) { fromType = fromType.GetGenericArguments()[0]; } | |
TypeCode fromTypeCode = Type.GetTypeCode(fromType); | |
IConvertible convertible = value as IConvertible; | |
switch (fromTypeCode) { | |
case TypeCode.Boolean: return (Boolean)value ? '1' : '0'; | |
case TypeCode.Char: | |
case TypeCode.SByte: | |
case TypeCode.Int16: | |
case TypeCode.Int32: | |
case TypeCode.Int64: | |
case TypeCode.Byte: | |
case TypeCode.UInt16: | |
case TypeCode.UInt32: | |
case TypeCode.UInt64: | |
case TypeCode.Single: | |
case TypeCode.Double: | |
case TypeCode.Decimal: | |
case TypeCode.DateTime: | |
return convertible.ToDouble(defaultProvider); | |
default: return base.ConvertFrom(context, culture, value); | |
} | |
} | |
} | |
private class MyDecimalConverter : DecimalConverter { | |
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) => base.CanConvertFrom(context, sourceType) || typeof(IConvertible).IsAssignableFrom(sourceType); | |
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { | |
if (value is null) { return base.ConvertFrom(context, culture, value); } | |
Type fromType = value.GetType(); | |
if (fromType.IsNullable()) { fromType = fromType.GetGenericArguments()[0]; } | |
TypeCode fromTypeCode = Type.GetTypeCode(fromType); | |
IConvertible convertible = value as IConvertible; | |
switch (fromTypeCode) { | |
case TypeCode.Boolean: return (Boolean)value ? '1' : '0'; | |
case TypeCode.Char: | |
case TypeCode.SByte: | |
case TypeCode.Int16: | |
case TypeCode.Int32: | |
case TypeCode.Int64: | |
case TypeCode.Byte: | |
case TypeCode.UInt16: | |
case TypeCode.UInt32: | |
case TypeCode.UInt64: | |
case TypeCode.Single: | |
case TypeCode.Double: | |
case TypeCode.Decimal: | |
case TypeCode.DateTime: | |
return convertible.ToDecimal(defaultProvider); | |
default: return base.ConvertFrom(context, culture, value); | |
} | |
} | |
} | |
private class MyDateTimeConverter : DateTimeConverter { | |
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) => base.CanConvertFrom(context, sourceType) || typeof(IConvertible).IsAssignableFrom(sourceType); | |
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { | |
if (value is null) { return base.ConvertFrom(context, culture, value); } | |
Type fromType = value.GetType(); | |
if (fromType.IsNullable()) { fromType = fromType.GetGenericArguments()[0]; } | |
TypeCode fromTypeCode = Type.GetTypeCode(fromType); | |
IConvertible convertible = value as IConvertible; | |
switch (fromTypeCode) { | |
case TypeCode.Boolean: return (Boolean)value ? DateTime.MaxValue : DateTime.MinValue; | |
case TypeCode.Char: | |
case TypeCode.SByte: | |
case TypeCode.Int16: | |
case TypeCode.Int32: | |
case TypeCode.Int64: | |
case TypeCode.Byte: | |
case TypeCode.UInt16: | |
case TypeCode.UInt32: | |
case TypeCode.UInt64: | |
case TypeCode.Single: | |
case TypeCode.Double: | |
case TypeCode.Decimal: | |
case TypeCode.DateTime: | |
return convertible.ToDateTime(defaultProvider); | |
default: return base.ConvertFrom(context, culture, value); | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment