public class MyApi { public MyApi() { _createdAt = DateTime.Now; } private DateTime _createdAt; public int ShowTimes { get; private set; } public void ShowCreateTime() { Console.WriteLine(_createdAt); ShowTimes++; } } void Main() { var api = new MyApi(); var field = api.GetType().GetField("_createdAt", BindingFlags.NonPublic | BindingFlags.Instance); var value = field.GetValue(api); Console.WriteLine(value); }这种写法并不优雅:
2.实现比较绕,不太直观。
void Main() { var api = new MyApi(); dynamic wrapper = ReflectionDynamicObject.Wrap(api); Console.WriteLine(wrapper._createdAt); }除了支持获取值,ReflectionDynamicObject 还支持赋值:
void Main() { var api = new MyApi(); dynamic wrapper = ReflectionDynamicObject.Wrap(api); wrapper._createdAt = new DateTime(2022, 2, 2, 22, 22, 22); api.ShowCreateTime(); }除了字段,当然也支持对属性的操作:
void Main() { var api = new MyApi(); dynamic wrapper = ReflectionDynamicObject.Wrap(api); wrapper.ShowTimes = 100; Console.WriteLine(wraper.ShowTimes); }在对属性的支持上,ReflectionDynamicObject 使用了“快速反射”技术,将取值和复制操作生成了委托以优化性能。
public sealed class ReflectionDynamicObject : DynamicObject { // 堆代码 duidaima.com private readonly object _instance; private readonly Accessor _accessor; private ReflectionDynamicObject(object instance) { _instance = instance ?? throw new ArgumentNullException(nameof(instance)); _accessor = GetAccessor(instance.GetType()); } public static ReflectionDynamicObject Wrap(Object value) { if (value == null) throw new ArgumentNullException(nameof(value)); return new ReflectionDynamicObject(value); } public override bool TryGetMember(GetMemberBinder binder, out object result) { if (_accessor.TryFindGetter(binder.Name, out var getter)) { result = getter.Get(_instance); return true; } return base.TryGetMember(binder, out result); } public override bool TrySetMember(SetMemberBinder binder, object value) { if (_accessor.TryFindSetter(binder.Name, out var setter)) { setter.Set(_instance, value); return true; } return base.TrySetMember(binder, value); } #region 快速反射 private interface IGetter { object Get(object instance); } private interface ISetter { void Set(object instance, object value); } private class Getter : IGetter { private FieldInfo _field; public Getter(FieldInfo field) { _field = field ?? throw new ArgumentNullException(nameof(field)); } public object Get(object instance) { return _field.GetValue(instance); } } private class Setter : ISetter { private FieldInfo _field; public Setter(FieldInfo field) { _field = field ?? throw new ArgumentNullException(nameof(field)); } public void Set(object instance, object value) { _field.SetValue(instance, value); } } private class Getter<T1, T2> : IGetter { private readonly Func<T1, T2> _getter; public Getter(Func<T1, T2> getter) { _getter = getter ?? throw new ArgumentNullException(nameof(getter)); } public object Get(object instance) { return _getter((T1)instance); } } private class Setter<T1, T2> : ISetter { private readonly Action<T1, T2> _setter; public Setter(Action<T1, T2> setter) { this._setter = setter ?? throw new ArgumentNullException(nameof(setter)); } public void Set(object instance, object value) { this._setter.Invoke((T1)instance, (T2)value); } } private class Accessor { public Accessor(Type type) { this._type = type ?? throw new ArgumentNullException(nameof(_type)); var getter = new SortedDictionary<string, IGetter>(); var setter = new SortedDictionary<string, ISetter>(); var fields = _type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (var field in fields) { getter[field.Name] = new Getter(field); setter[field.Name] = new Setter(field); } var props = _type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (var item in props) { if (item.CanRead) { var method = item.GetMethod; var funcType = typeof(Func<,>).MakeGenericType(item.DeclaringType, item.PropertyType); var func = method.CreateDelegate(funcType); var getterType = typeof(Getter<,>).MakeGenericType(item.DeclaringType, item.PropertyType); var get = (IGetter)Activator.CreateInstance(getterType, func); getter[item.Name] = get; } if (item.CanWrite) { var method = item.SetMethod; var actType = typeof(Action<,>).MakeGenericType(item.DeclaringType, item.PropertyType); var act = method.CreateDelegate(actType); var setterType = typeof(Setter<,>).MakeGenericType(item.DeclaringType, item.PropertyType); var set = (ISetter)Activator.CreateInstance(setterType, act); setter[item.Name] = set; } } _getters = getter; _setters = setter; } private readonly Type _type; private readonly IReadOnlyDictionary<string, IGetter> _getters; private readonly IReadOnlyDictionary<string, ISetter> _setters; public bool TryFindGetter(string name, out IGetter getter) => _getters.TryGetValue(name, out getter); public bool TryFindSetter(string name, out ISetter setter) => _setters.TryGetValue(name, out setter); } private static Dictionary<Type, Accessor> _accessors = new Dictionary<Type, Accessor>(); private static object _accessorsLock = new object(); private static Accessor GetAccessor(Type type) { if (_accessors.TryGetValue(type, out var accessor)) return accessor; lock (_accessorsLock) { if (_accessors.TryGetValue(type, out accessor)) return accessor; accessor = new Accessor(type); var temp = new Dictionary<Type, Accessor>(_accessors); temp[type] = new Accessor(type); _accessors = temp; return accessor; } } #endregion }