Skip to content

Instantly share code, notes, and snippets.

@DerekZiemba
Created March 12, 2018 08:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DerekZiemba/468b84d7b5a5a289470859e261f17217 to your computer and use it in GitHub Desktop.
Save DerekZiemba/468b84d7b5a5a289470859e261f17217 to your computer and use it in GitHub Desktop.
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