From 8c70c8d534d3b488fc8e1d619b3aa953e42e9425 Mon Sep 17 00:00:00 2001 From: Chris Cameron Date: Thu, 15 Oct 2020 14:30:46 -0400 Subject: [PATCH] refactor: ReflectionExtensions are generic, support for non-public members, reduced duplicate code --- .../Extensions/ReflectionExtensionsTest.cs | 26 ++-- .../Extensions/ReflectionExtensions.cs | 119 +++++++++--------- 2 files changed, 74 insertions(+), 71 deletions(-) diff --git a/ICD.Common.Utils.Tests/Extensions/ReflectionExtensionsTest.cs b/ICD.Common.Utils.Tests/Extensions/ReflectionExtensionsTest.cs index 8b0dac8..2200eb2 100644 --- a/ICD.Common.Utils.Tests/Extensions/ReflectionExtensionsTest.cs +++ b/ICD.Common.Utils.Tests/Extensions/ReflectionExtensionsTest.cs @@ -197,23 +197,33 @@ namespace ICD.Common.Utils.Tests.Extensions { var testClass = new PropertyTestClass(); + object instance; + // Test GetPropertyInfo at various levels Assert.AreEqual(testClass.GetType().GetProperty("PropertyString"), - testClass.GetPropertyInfo("PropertyString"), + testClass.GetPropertyInfo(out instance, "PropertyString"), "First level property not expected value"); + Assert.AreEqual(testClass, instance, "Unexpected property parent"); Assert.AreEqual(testClass.InternalClass.GetType().GetProperty("InternalPropertyString"), - testClass.GetPropertyInfo("InternalClass", "InternalPropertyString"), + testClass.GetPropertyInfo(out instance, "InternalClass", "InternalPropertyString"), "Second level property not expected value"); + Assert.AreEqual(testClass.InternalClass, instance, "Unexpected property parent"); Assert.AreEqual(testClass.InternalClass.DeepClass.GetType().GetProperty("DeepPropertyString"), - testClass.GetPropertyInfo("InternalClass", "DeepClass", "DeepPropertyString"), + testClass.GetPropertyInfo(out instance, "InternalClass", "DeepClass", "DeepPropertyString"), "Third level property not expected value"); + Assert.AreEqual(testClass.InternalClass.DeepClass, instance, "Unexpected property parent"); // Property that doesn't exits should return null - Assert.IsNull(testClass.GetPropertyInfo("InternalClass", "DeepClass", "NonExistent")); - Assert.IsNull(testClass.GetPropertyInfo("FakeFirstLevel", "FakeSecondLevel" , "FakeThridLevel")); - Assert.IsNull(testClass.GetPropertyInfo("InternalClass", "FakeSecondLevel", "ThirdLevelCanNotBeReal")); - Assert.IsNull(testClass.GetPropertyInfo("InternalClass", "FakeSecondLevel")); - Assert.IsNull(testClass.GetPropertyInfo("FakeFirstLevel")); + Assert.IsNull(testClass.GetPropertyInfo(out instance, "InternalClass", "DeepClass", "NonExistent")); + Assert.IsNull(instance); + Assert.IsNull(testClass.GetPropertyInfo(out instance, "FakeFirstLevel", "FakeSecondLevel" , "FakeThridLevel")); + Assert.IsNull(instance); + Assert.IsNull(testClass.GetPropertyInfo(out instance, "InternalClass", "FakeSecondLevel", "ThirdLevelCanNotBeReal")); + Assert.IsNull(instance); + Assert.IsNull(testClass.GetPropertyInfo(out instance, "InternalClass", "FakeSecondLevel")); + Assert.IsNull(instance); + Assert.IsNull(testClass.GetPropertyInfo(out instance, "FakeFirstLevel")); + Assert.IsNull(instance); } diff --git a/ICD.Common.Utils/Extensions/ReflectionExtensions.cs b/ICD.Common.Utils/Extensions/ReflectionExtensions.cs index 28e109d..1b0d420 100644 --- a/ICD.Common.Utils/Extensions/ReflectionExtensions.cs +++ b/ICD.Common.Utils/Extensions/ReflectionExtensions.cs @@ -173,37 +173,17 @@ namespace ICD.Common.Utils.Extensions { if (extends == null) throw new ArgumentNullException("extends"); + if (path == null) throw new ArgumentNullException("path"); - object currentObject = extends; + object instance; + PropertyInfo property = extends.GetPropertyInfo(out instance, path); - //Grab property values until the last item in the path - for (int i = 0; i < path.Length - 1; i++) - { - PropertyInfo info = - currentObject.GetType() -#if SIMPLSHARP - .GetCType() -#endif - .GetProperty(path[i]); - - if (info == null) - return false; - currentObject = info.GetValue(currentObject); - } - - //Set the property to the value - PropertyInfo finalPath = - currentObject.GetType() -#if SIMPLSHARP - .GetCType() -#endif - .GetProperty(path[path.Length - 1]); - if (finalPath == null) + if (property == null) return false; - finalPath.SetValue(currentObject, value); + property.SetValue(instance, value); return true; } @@ -212,37 +192,57 @@ namespace ICD.Common.Utils.Extensions /// Traverses the path to access properties nested in other properties /// /// + /// /// - /// true if property get was successful, false if the property was not found + /// [CanBeNull] - public static PropertyInfo GetPropertyInfo([NotNull] this object extends, [NotNull] params string[] path) + public static PropertyInfo GetPropertyInfo([NotNull] this object extends, out object instance, [NotNull] params string[] path) { if (extends == null) throw new ArgumentNullException("extends"); + if (path == null) throw new ArgumentNullException("path"); - object currentObject = extends; + instance = extends; - //Grab property values until the last item in the path + // Grab properties until the last item in the path for (int i = 0; i < path.Length - 1; i++) { - PropertyInfo info = currentObject.GetType() + PropertyInfo info = + instance.GetType() #if SIMPLSHARP - .GetCType() + .GetCType() #endif - .GetProperty(path[i]); + .GetProperty(path[i], + BindingFlags.Instance | + BindingFlags.Static | + BindingFlags.Public | + BindingFlags.NonPublic); if (info == null) + { + instance = null; return null; - currentObject = info.GetValue(currentObject); + } + + instance = info.GetValue(instance); } - //Set the property to the value - return currentObject.GetType() + // Set the property to the value + PropertyInfo output = + instance.GetType() #if SIMPLSHARP - .GetCType() + .GetCType() #endif - .GetProperty(path[path.Length - 1]); + .GetProperty(path[path.Length - 1], + BindingFlags.Instance | + BindingFlags.Static | + BindingFlags.Public | + BindingFlags.NonPublic); + + if (output == null) + instance = null; + return output; } /// @@ -253,35 +253,23 @@ namespace ICD.Common.Utils.Extensions /// /// /// true if property get was successful, false if the property was not found - public static bool GetProperty([NotNull] this object extends, [CanBeNull] out object value, [NotNull] params string[] path) + public static bool GetProperty([NotNull] this object extends, [CanBeNull] out T value, [NotNull] params string[] path) { if (extends == null) throw new ArgumentNullException("extends"); + if (path == null) throw new ArgumentNullException("path"); - value = null; + value = default(T); - object currentObject = extends; + object instance; + PropertyInfo property = extends.GetPropertyInfo(out instance, path); - //Grab property values - foreach (string node in path) - { - PropertyInfo info = - currentObject.GetType() -#if SIMPLSHARP - .GetCType() -#endif - .GetProperty(node); + if (property == null) + return false; - if (info == null) - return false; - - currentObject = info.GetValue(currentObject); - } - - //set the last value and return - value = currentObject; + value = (T)property.GetValue(instance); return true; } @@ -291,7 +279,7 @@ namespace ICD.Common.Utils.Extensions return CallMethod(extends, methodName, out value, new object[] { }); } - public static bool CallMethod([NotNull] this object extends, string methodName, [CanBeNull] out object value) + public static bool CallMethod([NotNull] this object extends, string methodName, [CanBeNull] out T value) { return CallMethod(extends, methodName, out value, new object[] { }); } @@ -302,25 +290,30 @@ namespace ICD.Common.Utils.Extensions return CallMethod(extends, methodName, out value, parameters); } - public static bool CallMethod([NotNull] this object extends, string methodName, [CanBeNull] out object value, [NotNull] params object[] parameters) + public static bool CallMethod([NotNull] this object extends, string methodName, [CanBeNull] out T value, [NotNull] params object[] parameters) { if (extends == null) throw new ArgumentNullException("extends"); + if (parameters == null) throw new ArgumentNullException("parameters"); - value = false; + value = default(T); MethodInfo method = extends.GetType() #if SIMPLSHARP .GetCType() #endif - .GetMethod(methodName); + .GetMethod(methodName, + BindingFlags.Instance | + BindingFlags.Static | + BindingFlags.Public | + BindingFlags.NonPublic); if (method == null) return false; - value = method.Invoke(extends, parameters); + value = (T)method.Invoke(extends, parameters); return true; } @@ -339,7 +332,7 @@ namespace ICD.Common.Utils.Extensions return eventHandlerType == typeof(EventHandler) ? typeof(EventArgs) : eventHandlerType.GetInnerGenericTypes(typeof(EventHandler<>)) - .First(); + .Single(); } } }