using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Text; [assembly: InternalsVisibleTo("Raindrops.SharedTests")] namespace Raindrops.Shared.InvokeST { public static class AccessorHelper { internal static readonly ConcurrentDictionary> s_map; internal static readonly BindingFlags s_flag; static AccessorHelper() { s_map = new ConcurrentDictionary>(); s_flag = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static; } public static string CreateKey(string prefix, string member, Type retType, int parameterCount) { return $"{prefix}.{member}.{retType.FullName}.{parameterCount}"; } public static void ClearCache(Assembly assembly) { foreach (Type key in s_map.Keys.ToArray()) { if (key.Assembly == assembly) { s_map.TryRemove(key, out _); } } } public static GetHandler GetGetHandler(ConcurrentDictionary dic, Type type, string member) { string key = CreateKey("GetHandler", member, typeof(T), 0); return dic.GetOrAdd(key, (o) => { lock (dic) { GetHandler getHandler = null; PropertyInfo propertyInfo = type.GetProperty(member, s_flag); if (propertyInfo == null) { FieldInfo fieldInfo = type.GetField(member, s_flag); if (fieldInfo != null) { getHandler = InvokeHandlerHelper.CreateGetHandler(fieldInfo); } } else { getHandler = InvokeHandlerHelper.CreateGetHandler(propertyInfo); } return getHandler; } }) as GetHandler; } public static SetHandler GetSetHandler(ConcurrentDictionary dic, Type type, string member) { string key = CreateKey("SetHandler", member, typeof(T), 1); return dic.GetOrAdd(key, (o) => { lock (dic) { SetHandler setHandler = null; PropertyInfo propertyInfo = type.GetProperty(member, s_flag); if (propertyInfo == null) { FieldInfo fieldInfo = type.GetField(member, s_flag); if (fieldInfo != null) { setHandler = InvokeHandlerHelper.CreateSetHandler(fieldInfo); } } else { setHandler = InvokeHandlerHelper.CreateSetHandler(propertyInfo); } return setHandler; } }) as SetHandler; } public static bool TryGetValue(this object target, Type type, string member, out T value) { if (type != null) { ConcurrentDictionary dic = s_map.GetOrAdd(type, (k) => new ConcurrentDictionary()); GetHandler get = GetGetHandler(dic, type, member); if (get != null) { value = get(target); return true; } } value = default; return false; } public static bool TryGetValue(this object target, string member, out T value) { if (target != null) { return TryGetValue(target, target.GetType(), member, out value); } value = default; return false; } public static bool TrySetValue(this object target, Type type, string member, T value) { if (type != null) { ConcurrentDictionary dic = s_map.GetOrAdd(type, (k) => new ConcurrentDictionary()); SetHandler get = GetSetHandler(dic, type, member); if (get != null) { get(target, value); return true; } } value = default; return false; } public static bool TrySetValue(this object target, string member, T value) { if (target != null) { return TrySetValue(target, target.GetType(), member, value); } value = default; return false; } public static T GetValue(this object target, Type type, string member) { return TryGetValue(target, type, member, out T value) ? value : throw new ArgumentException(nameof(member)); } public static T GetValue(this object target, string member) { return GetValue(target, target?.GetType(), member); } public static void SetValue(this object target, Type type, string member, T value) { if (!TrySetValue(target, type, member, value)) throw new ArgumentException(nameof(member)); } public static void SetValue(this object target, string member, T value) { SetValue(target, target?.GetType(), member, value); } } }