|
| 1 | +#if !NETSTANDARD1_3 // needs the component-model API |
| 2 | +using System; |
| 3 | +using System.Collections.Generic; |
| 4 | +using System.ComponentModel; |
| 5 | + |
| 6 | +namespace Dapper |
| 7 | +{ |
| 8 | + public static partial class SqlMapper |
| 9 | + { |
| 10 | + [TypeDescriptionProvider(typeof(DapperRowTypeDescriptionProvider))] |
| 11 | + private sealed partial class DapperRow |
| 12 | + { |
| 13 | + private sealed class DapperRowTypeDescriptionProvider : TypeDescriptionProvider |
| 14 | + { |
| 15 | + public override ICustomTypeDescriptor GetExtendedTypeDescriptor(object instance) |
| 16 | + => new DapperRowTypeDescriptor(instance); |
| 17 | + public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance) |
| 18 | + => new DapperRowTypeDescriptor(instance); |
| 19 | + } |
| 20 | + |
| 21 | + //// in theory we could implement this for zero-length results to bind; would require |
| 22 | + //// additional changes, though, to capture a table even when no rows - so not currently provided |
| 23 | + //internal sealed class DapperRowList : List<DapperRow>, ITypedList |
| 24 | + //{ |
| 25 | + // private readonly DapperTable _table; |
| 26 | + // public DapperRowList(DapperTable table) { _table = table; } |
| 27 | + // PropertyDescriptorCollection ITypedList.GetItemProperties(PropertyDescriptor[] listAccessors) |
| 28 | + // { |
| 29 | + // if (listAccessors != null && listAccessors.Length != 0) return PropertyDescriptorCollection.Empty; |
| 30 | + |
| 31 | + // return DapperRowTypeDescriptor.GetProperties(_table); |
| 32 | + // } |
| 33 | + |
| 34 | + // string ITypedList.GetListName(PropertyDescriptor[] listAccessors) => null; |
| 35 | + //} |
| 36 | + |
| 37 | + private sealed class DapperRowTypeDescriptor : ICustomTypeDescriptor |
| 38 | + { |
| 39 | + private readonly DapperRow _row; |
| 40 | + public DapperRowTypeDescriptor(object instance) |
| 41 | + => _row = (DapperRow)instance; |
| 42 | + |
| 43 | + AttributeCollection ICustomTypeDescriptor.GetAttributes() |
| 44 | + => AttributeCollection.Empty; |
| 45 | + |
| 46 | + string ICustomTypeDescriptor.GetClassName() => typeof(DapperRow).FullName; |
| 47 | + |
| 48 | + string ICustomTypeDescriptor.GetComponentName() => null; |
| 49 | + |
| 50 | + private static readonly TypeConverter s_converter = new ExpandableObjectConverter(); |
| 51 | + TypeConverter ICustomTypeDescriptor.GetConverter() => s_converter; |
| 52 | + |
| 53 | + EventDescriptor ICustomTypeDescriptor.GetDefaultEvent() => null; |
| 54 | + |
| 55 | + PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty() => null; |
| 56 | + |
| 57 | + object ICustomTypeDescriptor.GetEditor(Type editorBaseType) => null; |
| 58 | + |
| 59 | + EventDescriptorCollection ICustomTypeDescriptor.GetEvents() => EventDescriptorCollection.Empty; |
| 60 | + |
| 61 | + EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes) => EventDescriptorCollection.Empty; |
| 62 | + |
| 63 | + internal static PropertyDescriptorCollection GetProperties(DapperRow row) => GetProperties(row?.table, row); |
| 64 | + internal static PropertyDescriptorCollection GetProperties(DapperTable table, IDictionary<string,object> row = null) |
| 65 | + { |
| 66 | + string[] names = table?.FieldNames; |
| 67 | + if (names == null || names.Length == 0) return PropertyDescriptorCollection.Empty; |
| 68 | + var arr = new PropertyDescriptor[names.Length]; |
| 69 | + for (int i = 0; i < arr.Length; i++) |
| 70 | + { |
| 71 | + var type = row != null && row.TryGetValue(names[i], out var value) && value != null |
| 72 | + ? value.GetType() : typeof(object); |
| 73 | + arr[i] = new RowBoundPropertyDescriptor(type, names[i]); |
| 74 | + } |
| 75 | + return new PropertyDescriptorCollection(arr, true); |
| 76 | + } |
| 77 | + PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties() => GetProperties(_row); |
| 78 | + |
| 79 | + PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes) => GetProperties(_row); |
| 80 | + |
| 81 | + object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd) => _row; |
| 82 | + } |
| 83 | + |
| 84 | + private sealed class RowBoundPropertyDescriptor : PropertyDescriptor |
| 85 | + { |
| 86 | + private readonly Type _type; |
| 87 | + public RowBoundPropertyDescriptor(Type type, string name) : base(name, null) |
| 88 | + => _type = type; |
| 89 | + |
| 90 | + public override bool CanResetValue(object component) => false; |
| 91 | + public override void ResetValue(object component) => throw new NotSupportedException(); |
| 92 | + |
| 93 | + public override bool IsReadOnly => false; |
| 94 | + public override bool ShouldSerializeValue(object component) => true; |
| 95 | + public override Type ComponentType => typeof(DapperRow); |
| 96 | + public override Type PropertyType => _type; |
| 97 | + public override object GetValue(object component) |
| 98 | + => ((IDictionary<string, object>)component).TryGetValue(Name, out var val) ? val : null; |
| 99 | + public override void SetValue(object component, object value) |
| 100 | + => ((IDictionary<string, object>)component)[Name] = value; |
| 101 | + } |
| 102 | + } |
| 103 | + } |
| 104 | +} |
| 105 | +#endif |
0 commit comments