TypeConverterBinder.cs 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Diagnostics.CodeAnalysis;
  5. using System.Globalization;
  6. namespace FastGithub.Configuration
  7. {
  8. /// <summary>
  9. /// TypeConverter类型转换绑定器
  10. /// </summary>
  11. static class TypeConverterBinder
  12. {
  13. private static readonly Dictionary<Type, Binder> binders = new();
  14. /// <summary>
  15. /// 绑定转换器到指定类型
  16. /// </summary>
  17. /// <typeparam name="T"></typeparam>
  18. /// <param name="reader"></param>
  19. /// <param name="writer"></param>
  20. public static void Bind<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(Func<string, T?> reader, Func<T?, string?> writer)
  21. {
  22. binders[typeof(T)] = new Binder<T>(reader, writer);
  23. var converterType = typeof(TypeConverter<>).MakeGenericType(typeof(T));
  24. if (TypeDescriptor.GetConverter(typeof(T)).GetType() != converterType)
  25. {
  26. TypeDescriptor.AddAttributes(typeof(T), new TypeConverterAttribute(converterType));
  27. }
  28. }
  29. private abstract class Binder
  30. {
  31. public abstract object? Read(string value);
  32. public abstract string? Write(object? value);
  33. }
  34. private class Binder<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T> : Binder
  35. {
  36. private readonly Func<string, T?> reader;
  37. private readonly Func<T?, string?> writer;
  38. public Binder(Func<string, T?> reader, Func<T?, string?> writer)
  39. {
  40. this.reader = reader;
  41. this.writer = writer;
  42. }
  43. public override object? Read(string value)
  44. {
  45. return this.reader(value);
  46. }
  47. public override string? Write(object? value)
  48. {
  49. return this.writer((T?)value);
  50. }
  51. }
  52. private class TypeConverter<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T> : TypeConverter
  53. {
  54. public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
  55. {
  56. return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
  57. }
  58. public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
  59. {
  60. if (value is string stringVal)
  61. {
  62. if (stringVal.Equals(string.Empty))
  63. {
  64. return default(T);
  65. }
  66. else if (binders.TryGetValue(typeof(T), out var binder))
  67. {
  68. return binder.Read(stringVal);
  69. }
  70. }
  71. return base.ConvertFrom(context, culture, value);
  72. }
  73. public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType)
  74. {
  75. return destinationType == typeof(T) && binders.TryGetValue(destinationType, out var binder)
  76. ? binder.Write(value)
  77. : base.ConvertTo(context, culture, value, destinationType);
  78. }
  79. }
  80. }
  81. }