using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Globalization; namespace FastGithub.Configuration { /// /// TypeConverter类型转换绑定器 /// static class TypeConverterBinder { private static readonly Dictionary binders = new(); /// /// 绑定转换器到指定类型 /// /// /// /// public static void Bind<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(Func reader, Func writer) { binders[typeof(T)] = new Binder(reader, writer); var converterType = typeof(TypeConverter<>).MakeGenericType(typeof(T)); if (TypeDescriptor.GetConverter(typeof(T)).GetType() != converterType) { TypeDescriptor.AddAttributes(typeof(T), new TypeConverterAttribute(converterType)); } } private abstract class Binder { public abstract object? Read(string value); public abstract string? Write(object? value); } private class Binder<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T> : Binder { private readonly Func reader; private readonly Func writer; public Binder(Func reader, Func writer) { this.reader = reader; this.writer = writer; } public override object? Read(string value) { return this.reader(value); } public override string? Write(object? value) { return this.writer((T?)value); } } private class TypeConverter<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T> : TypeConverter { public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType) { return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType); } public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value) { if (value is string stringVal) { if (stringVal.Equals(string.Empty)) { return default(T); } else if (binders.TryGetValue(typeof(T), out var binder)) { return binder.Read(stringVal); } } return base.ConvertFrom(context, culture, value); } public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType) { return destinationType == typeof(T) && binders.TryGetValue(destinationType, out var binder) ? binder.Write(value) : base.ConvertTo(context, culture, value, destinationType); } } } }