/// <summary> /// Initialises a new instance of the CSPlugin class /// </summary> public CSPlugin() { // Initialise hooks = new Dictionary <string, MethodInfo>(); // Find all hooks foreach (MethodInfo method in GetType().GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)) { object[] attr = method.GetCustomAttributes(typeof(HookMethod), true); if (attr.Length > 0) { HookMethod hookmethod = attr[0] as HookMethod; hooks.Add(hookmethod.Name, method); } } }
protected List <HookMethod> FindHooks(string name, object[] args) { HookCache hookCache; object[] defaultValue; bool flag; List <HookMethod> hookMethod = this.HooksCache.GetHookMethod(name, args, out hookCache); if (hookMethod != null) { return(hookMethod); } List <HookMethod> hookMethods = new List <HookMethod>(); if (!this.Hooks.TryGetValue(name, out hookMethod)) { return(hookMethods); } HookMethod hookMethod1 = null; HookMethod hookMethod2 = null; foreach (HookMethod hookMethod3 in hookMethod) { if (!hookMethod3.IsBaseHook) { int num = (args != null ? (int)args.Length : 0); bool flag1 = false; if (num == (int)hookMethod3.Parameters.Length) { defaultValue = args; } else { defaultValue = ArrayPool.Get((int)hookMethod3.Parameters.Length); flag1 = true; if (num > 0 && defaultValue.Length != 0) { Array.Copy(args, defaultValue, Math.Min(num, (int)defaultValue.Length)); } if ((int)defaultValue.Length > num) { for (int i = num; i < (int)defaultValue.Length; i++) { ParameterInfo parameters = hookMethod3.Parameters[i]; if (parameters.DefaultValue != null && parameters.DefaultValue != DBNull.Value) { defaultValue[i] = parameters.DefaultValue; } else if (parameters.ParameterType.IsValueType) { defaultValue[i] = Activator.CreateInstance(parameters.ParameterType); } } } } if (hookMethod3.HasMatchingSignature(defaultValue, out flag)) { if (!flag) { hookMethod2 = hookMethod3; } else { hookMethod1 = hookMethod3; if (hookMethod1 != null) { hookMethods.Add(hookMethod1); } else if (hookMethod2 != null) { hookMethods.Add(hookMethod2); } hookCache.SetupMethods(hookMethods); return(hookMethods); } } if (!flag1) { continue; } ArrayPool.Free(defaultValue); } else { hookMethods.Add(hookMethod3); } } if (hookMethod1 != null) { hookMethods.Add(hookMethod1); } else if (hookMethod2 != null) { hookMethods.Add(hookMethod2); } hookCache.SetupMethods(hookMethods); return(hookMethods); }
protected virtual object InvokeMethod(HookMethod method, object[] args) { return(method.Method.Invoke(this, args)); }
protected virtual object InvokeMethod(HookMethod method, object[] args) => method.Method.Invoke(this, args);
protected List <HookMethod> FindHooks(string name, object[] args) { // Get the full name of the hook `name(argument type 1, argument type 2, ..., argument type x)` var fullName = name; if (args?.Length > 0) { fullName += $"({string.Join(", ", args.Select(x => x?.GetType().ToString() ?? "null").ToArray())})"; } // Check the cache if we already found a match for this hook if (HooksCache.ContainsKey(fullName)) { return(HooksCache[fullName]); } List <HookMethod> methods; var matches = new List <HookMethod>(); // Get all hook methods that could match, return an empty list if none match if (!Hooks.TryGetValue(name, out methods)) { return(matches); } // Find matching hooks HookMethod exactMatch = null; HookMethod overloadedMatch = null; foreach (var h in methods) { // A base hook should always have a matching signature either directly or through inheritance // and should always be called as core functionality depends on it. if (h.IsBaseHook) { matches.Add(h); continue; } // Check if this method matches the hook arguments passed if it isn't a base hook object[] hookArgs; var received = args?.Length ?? 0; if (received != h.Parameters.Length) { // The call argument count is different to the declared callback methods argument count hookArgs = new object[h.Parameters.Length]; if (received > 0 && hookArgs.Length > 0) { // Remove any additional arguments which the callback method does not declare Array.Copy(args, hookArgs, Math.Min(received, hookArgs.Length)); } if (hookArgs.Length > received) { // Create additional parameters for arguments excluded in this hook call for (var n = received; n < hookArgs.Length; n++) { var parameter = h.Parameters[n]; if (parameter.DefaultValue != null && parameter.DefaultValue != DBNull.Value) { // Use the default value that was provided by the method definition hookArgs[n] = parameter.DefaultValue; } else if (parameter.ParameterType.IsValueType) { // Use the default value for value types hookArgs[n] = Activator.CreateInstance(parameter.ParameterType); } } } } else { hookArgs = args; } bool isExactMatch; if (h.HasMatchingSignature(hookArgs, out isExactMatch)) { if (isExactMatch) { exactMatch = h; break; } // Should we determine the level and call the closest overloaded match? Performance impact? overloadedMatch = h; } } if (exactMatch != null) { matches.Add(exactMatch); } else { if (overloadedMatch != null) { matches.Add(overloadedMatch); } } return(HooksCache[fullName] = matches); }
public HookMatch(HookMethod method, object[] args) { Method = method; Args = args; }
protected List <HookMethod> FindHooks(string name, object[] args) { // Get the full name of the hook `name(argument type 1, argument type 2, ..., argument type x)` // Check the cache if we already found a match for this hook HookCache cache; List <HookMethod> methods = HooksCache.GetHookMethod(name, args, out cache); if (methods != null) { return(methods); } List <HookMethod> matches = new List <HookMethod>(); // Get all hook methods that could match, return an empty list if none match if (!Hooks.TryGetValue(name, out methods)) { return(matches); } // Find matching hooks HookMethod exactMatch = null; HookMethod overloadedMatch = null; foreach (HookMethod h in methods) { // A base hook should always have a matching signature either directly or through inheritance // and should always be called as core functionality depends on it. if (h.IsBaseHook) { matches.Add(h); continue; } // Check if this method matches the hook arguments passed if it isn't a base hook object[] hookArgs; int received = args?.Length ?? 0; bool pooledArray = false; if (received != h.Parameters.Length) { // The call argument count is different to the declared callback methods argument count hookArgs = ArrayPool.Get(h.Parameters.Length); pooledArray = true; if (received > 0 && hookArgs.Length > 0) { // Remove any additional arguments which the callback method does not declare Array.Copy(args, hookArgs, Math.Min(received, hookArgs.Length)); } if (hookArgs.Length > received) { // Create additional parameters for arguments excluded in this hook call for (int n = received; n < hookArgs.Length; n++) { ParameterInfo parameter = h.Parameters[n]; if (parameter.DefaultValue != null && parameter.DefaultValue != DBNull.Value) { // Use the default value that was provided by the method definition hookArgs[n] = parameter.DefaultValue; } else if (parameter.ParameterType.IsValueType) { // Use the default value for value types hookArgs[n] = Activator.CreateInstance(parameter.ParameterType); } } } } else { hookArgs = args; } bool isExactMatch; if (h.HasMatchingSignature(hookArgs, out isExactMatch)) { if (isExactMatch) { exactMatch = h; break; } // Should we determine the level and call the closest overloaded match? Performance impact? overloadedMatch = h; } if (pooledArray) { ArrayPool.Free(hookArgs); } } if (exactMatch != null) { matches.Add(exactMatch); } else { if (overloadedMatch != null) { matches.Add(overloadedMatch); } } cache.SetupMethods(matches); return(matches); }