SimpleDIAttribute.cs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Linq.Expressions;
  5. using System.Reflection;
  6. using com.bbbirder.injection;
  7. #if UNITY_2021_3_OR_NEWER && !NO_UNITY
  8. using UnityEngine;
  9. using UnityEngine.Scripting;
  10. #endif
  11. namespace com.bbbirder.injection
  12. {
  13. using static System.Reflection.BindingFlags;
  14. [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
  15. public class SimpleDIAttribute : InjectionAttribute
  16. {
  17. static MethodInfo s_MetaMethodInfo;
  18. static MethodInfo s_StaticMetaMethodInfo;
  19. static MethodInfo s_miMetaConstructor;
  20. public SimpleDIAttribute()
  21. {
  22. }
  23. bool IsStatic(MemberInfo memberInfo)
  24. {
  25. if (memberInfo is FieldInfo fieldInfo) return fieldInfo.IsStatic;
  26. if (memberInfo is PropertyInfo propertyInfo)
  27. {
  28. if (!propertyInfo.CanRead)
  29. {
  30. return propertyInfo.GetSetMethod(nonPublic: true).IsStatic;
  31. }
  32. return propertyInfo.GetGetMethod(nonPublic: true).IsStatic;
  33. }
  34. return false;
  35. }
  36. #if UNITY_2021_3_OR_NEWER && !NO_UNITY
  37. [Preserve]
  38. #endif
  39. static TFunc MetaConstructor<TFunc>(Action<object> action, Type instType, bool isStatic)
  40. where TFunc : Delegate
  41. {
  42. var argtypes = typeof(TFunc).GetGenericArguments();
  43. var act = Expression.Constant(action);
  44. var args = new List<ParameterExpression>(argtypes.Length + 1);
  45. // if (!isStatic) args.Add(Expression.Parameter(instType, "inst"));
  46. for (int i = 0; i < argtypes.Length; i++)
  47. {
  48. args.Add(Expression.Parameter(argtypes[i], "arg" + i));
  49. }
  50. var ivk = Expression.Call(act,
  51. typeof(Action<object>).GetMethod("Invoke"),
  52. isStatic ? Expression.Constant(null) : args[0]);
  53. var lambda = Expression.Lambda<TFunc>(ivk, args);
  54. return lambda.Compile();
  55. }
  56. ConstructorInfo[] Get_Ctors(Type type)
  57. {
  58. return type.GetConstructors(Public | NonPublic | Instance);
  59. }
  60. ConstructorInfo[] Get_CCtor(Type type)
  61. {
  62. return type.GetConstructors(Public | NonPublic | Static);
  63. }
  64. bool CanWrite(MemberInfo memberInfo)
  65. {
  66. if (memberInfo is FieldInfo) return true;
  67. if (memberInfo is PropertyInfo propertyInfo) return propertyInfo.CanWrite;
  68. return false;
  69. }
  70. void SetMemberValue(MemberInfo memberInfo, object inst, object value)
  71. {
  72. if (memberInfo is FieldInfo fi)
  73. {
  74. fi.SetValue(inst, value);
  75. return;
  76. }
  77. if (memberInfo is PropertyInfo pi)
  78. {
  79. pi.SetValue(inst, value);
  80. return;
  81. }
  82. }
  83. Type GetMemberType(MemberInfo memberInfo)
  84. {
  85. if (memberInfo is FieldInfo fi) return fi.FieldType;
  86. if (memberInfo is PropertyInfo pi) return pi.PropertyType;
  87. return default;
  88. }
  89. public override IEnumerable<InjectionInfo> ProvideInjections()
  90. {
  91. s_MetaMethodInfo ??= typeof(SimpleDIAttribute).GetMethod(nameof(MetaGet), Static | NonPublic);
  92. s_StaticMetaMethodInfo ??= typeof(SimpleDIAttribute).GetMethod(nameof(StaticMetaGet), Static | NonPublic);
  93. s_miMetaConstructor ??= typeof(SimpleDIAttribute).GetMethod(nameof(MetaConstructor), Static | NonPublic);
  94. if (targetInfo is not PropertyInfo and not FieldInfo)
  95. throw new Exception($"cannot inject {targetInfo} on type {targetInfo.DeclaringType}, only fields and properties allowed");
  96. var memberType = GetMemberType(targetInfo);
  97. var isStatic = IsStatic(targetInfo);
  98. var canWrite = CanWrite(targetInfo);
  99. // var declaringType = targetMember.DeclaringType;
  100. if (isStatic)
  101. {
  102. if (canWrite)
  103. {
  104. // set on fix instantly
  105. yield return InjectionInfo.Create(() =>
  106. {
  107. SetMemberValue(targetInfo, null, GetContainerInst(memberType, targetInfo.DeclaringType));
  108. });
  109. }
  110. else
  111. {
  112. // inject get method
  113. var propertyInfo = targetInfo as PropertyInfo;
  114. var fixingMethod = s_StaticMetaMethodInfo.MakeGenericMethod(propertyInfo.PropertyType, targetInfo.DeclaringType);
  115. yield return InjectionInfo.Create(
  116. propertyInfo.GetGetMethod(nonPublic: true),
  117. fixingMethod
  118. );
  119. }
  120. }
  121. else
  122. {
  123. if (canWrite)
  124. {
  125. // inject constructor
  126. var constructors = Get_Ctors(targetInfo.DeclaringType);
  127. var argtypes = new List<Type>();
  128. foreach (var constructor in constructors)
  129. {
  130. Delegate rawAction = default;
  131. argtypes.Clear();
  132. argtypes.Add(targetInfo.DeclaringType);
  133. foreach (var p in constructor.GetParameters())
  134. {
  135. argtypes.Add(p.ParameterType);
  136. }
  137. var miInstAction = default(Type);
  138. if (argtypes.Count == 0)
  139. {
  140. miInstAction = typeof(System.Action);
  141. }
  142. else
  143. {
  144. var miGenericAction = Type.GetType("System.Action`" + argtypes.Count);
  145. miInstAction = miGenericAction.MakeGenericType(argtypes.ToArray());
  146. }
  147. var miCtorInst = s_miMetaConstructor.MakeGenericMethod(miInstAction);
  148. var fixingFunc = miCtorInst.Invoke(null, new object[]{
  149. (Action<object>)fixedContructor,targetInfo.DeclaringType,isStatic
  150. }) as Delegate;
  151. yield return InjectionInfo.Create(
  152. constructor,
  153. fixingFunc,
  154. f => rawAction = f
  155. );
  156. void fixedContructor(object inst)
  157. {
  158. SetMemberValue(targetInfo, inst, GetContainerInst(memberType, targetInfo.DeclaringType));
  159. rawAction.GetType().GetMethod("Invoke").Invoke(rawAction, new[] { inst });
  160. }
  161. }
  162. }
  163. else
  164. {
  165. // inject get method
  166. var propertyInfo = targetInfo as PropertyInfo;
  167. var fixingMethod = s_MetaMethodInfo.MakeGenericMethod(targetInfo.DeclaringType, propertyInfo.PropertyType, targetInfo.DeclaringType);
  168. yield return InjectionInfo.Create(
  169. propertyInfo.GetGetMethod(nonPublic: true),
  170. fixingMethod
  171. );
  172. }
  173. }
  174. }
  175. #if UNITY_2021_3_OR_NEWER && !NO_UNITY
  176. [HideInCallstack]
  177. #endif
  178. static TRet MetaGet<T, TRet, TDecl>(T _) where T : class where TRet : class
  179. {
  180. return GetContainerInst(typeof(TRet), typeof(TDecl)) as TRet;
  181. }
  182. #if UNITY_2021_3_OR_NEWER && !NO_UNITY
  183. [HideInCallstack]
  184. #endif
  185. static TRet StaticMetaGet<TRet, TDecl>() where TRet : class
  186. {
  187. return GetContainerInst(typeof(TRet), typeof(TDecl)) as TRet;
  188. }
  189. #if UNITY_2021_3_OR_NEWER && !NO_UNITY
  190. [HideInCallstack]
  191. #endif
  192. static object GetContainerInst(Type desiredType, Type declaringType)
  193. {
  194. return ServiceContainer.Get(desiredType, declaringType, false);
  195. }
  196. }
  197. }