DynamicMemberAccess.cs 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. using System.Linq.Expressions;
  5. using System.Reflection;
  6. namespace VCommon.Reflection
  7. {
  8. public static class DynamicMemberAccess<TClass, TPropertyType>
  9. {
  10. private static readonly IDictionary<string, Func<TClass, TPropertyType>> CachedAccessors = new ConcurrentDictionary<string, Func<TClass, TPropertyType>>();
  11. private static readonly IDictionary<string, Func<TPropertyType>> CachedStaticAccessors = new ConcurrentDictionary<string, Func<TPropertyType>>();
  12. private static Func<TClass, TPropertyType> BuildInstanceAccessor(string memberName)
  13. {
  14. var pInstance = Expression.Parameter(typeof(TClass));
  15. var access = Expression.PropertyOrField(pInstance, memberName);
  16. var expression = Expression.Lambda(access, pInstance);
  17. var del = (Func<TClass, TPropertyType>)expression.Compile();
  18. return del;
  19. }
  20. private static Func<TPropertyType> BuildStaticAccessor(string memberName)
  21. {
  22. var member = (MemberInfo)typeof(TClass).GetProperty(memberName, BindingFlags.Static | BindingFlags.Public) ?? typeof(TClass).GetField(memberName, BindingFlags.Static | BindingFlags.Public);
  23. if (null == member) throw new ArgumentException("member not found of " + typeof(TClass).FullName, nameof(memberName));
  24. var access = Expression.MakeMemberAccess(null, member);
  25. var expression = Expression.Lambda(access);
  26. var del = (Func<TPropertyType>)expression.Compile();
  27. return del;
  28. }
  29. public static TPropertyType Read(TClass instance, string memberName)
  30. {
  31. if (false == CachedAccessors.TryGetValue(memberName, out var del))
  32. {
  33. del = BuildInstanceAccessor(memberName);
  34. CachedAccessors[memberName] = del;
  35. }
  36. return del(instance);
  37. }
  38. public static TPropertyType ReadStatic(string memberName)
  39. {
  40. if (false == CachedStaticAccessors.TryGetValue(memberName, out var del))
  41. {
  42. del = BuildStaticAccessor(memberName);
  43. CachedStaticAccessors[memberName] = del;
  44. }
  45. return del();
  46. }
  47. }
  48. }