refactor: ReflectionExtensions are generic, support for non-public members, reduced duplicate code

This commit is contained in:
Chris Cameron
2020-10-15 14:30:46 -04:00
parent 0d85fe8106
commit 8c70c8d534
2 changed files with 74 additions and 71 deletions

View File

@@ -197,23 +197,33 @@ namespace ICD.Common.Utils.Tests.Extensions
{ {
var testClass = new PropertyTestClass(); var testClass = new PropertyTestClass();
object instance;
// Test GetPropertyInfo at various levels // Test GetPropertyInfo at various levels
Assert.AreEqual(testClass.GetType().GetProperty("PropertyString"), Assert.AreEqual(testClass.GetType().GetProperty("PropertyString"),
testClass.GetPropertyInfo("PropertyString"), testClass.GetPropertyInfo(out instance, "PropertyString"),
"First level property not expected value"); "First level property not expected value");
Assert.AreEqual(testClass, instance, "Unexpected property parent");
Assert.AreEqual(testClass.InternalClass.GetType().GetProperty("InternalPropertyString"), Assert.AreEqual(testClass.InternalClass.GetType().GetProperty("InternalPropertyString"),
testClass.GetPropertyInfo("InternalClass", "InternalPropertyString"), testClass.GetPropertyInfo(out instance, "InternalClass", "InternalPropertyString"),
"Second level property not expected value"); "Second level property not expected value");
Assert.AreEqual(testClass.InternalClass, instance, "Unexpected property parent");
Assert.AreEqual(testClass.InternalClass.DeepClass.GetType().GetProperty("DeepPropertyString"), 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"); "Third level property not expected value");
Assert.AreEqual(testClass.InternalClass.DeepClass, instance, "Unexpected property parent");
// Property that doesn't exits should return null // Property that doesn't exits should return null
Assert.IsNull(testClass.GetPropertyInfo("InternalClass", "DeepClass", "NonExistent")); Assert.IsNull(testClass.GetPropertyInfo(out instance, "InternalClass", "DeepClass", "NonExistent"));
Assert.IsNull(testClass.GetPropertyInfo("FakeFirstLevel", "FakeSecondLevel" , "FakeThridLevel")); Assert.IsNull(instance);
Assert.IsNull(testClass.GetPropertyInfo("InternalClass", "FakeSecondLevel", "ThirdLevelCanNotBeReal")); Assert.IsNull(testClass.GetPropertyInfo(out instance, "FakeFirstLevel", "FakeSecondLevel" , "FakeThridLevel"));
Assert.IsNull(testClass.GetPropertyInfo("InternalClass", "FakeSecondLevel")); Assert.IsNull(instance);
Assert.IsNull(testClass.GetPropertyInfo("FakeFirstLevel")); 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);
} }

View File

@@ -173,37 +173,17 @@ namespace ICD.Common.Utils.Extensions
{ {
if (extends == null) if (extends == null)
throw new ArgumentNullException("extends"); throw new ArgumentNullException("extends");
if (path == null) if (path == null)
throw new ArgumentNullException("path"); 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 if (property == null)
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)
return false; return false;
finalPath.SetValue(currentObject, value); property.SetValue(instance, value);
return true; return true;
} }
@@ -212,37 +192,57 @@ namespace ICD.Common.Utils.Extensions
/// Traverses the path to access properties nested in other properties /// Traverses the path to access properties nested in other properties
/// </summary> /// </summary>
/// <param name="extends"></param> /// <param name="extends"></param>
/// <param name="instance"></param>
/// <param name="path"></param> /// <param name="path"></param>
/// <returns>true if property get was successful, false if the property was not found</returns> /// <returns></returns>
[CanBeNull] [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) if (extends == null)
throw new ArgumentNullException("extends"); throw new ArgumentNullException("extends");
if (path == null) if (path == null)
throw new ArgumentNullException("path"); 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++) for (int i = 0; i < path.Length - 1; i++)
{ {
PropertyInfo info = currentObject.GetType() PropertyInfo info =
instance.GetType()
#if SIMPLSHARP #if SIMPLSHARP
.GetCType() .GetCType()
#endif #endif
.GetProperty(path[i]); .GetProperty(path[i],
BindingFlags.Instance |
BindingFlags.Static |
BindingFlags.Public |
BindingFlags.NonPublic);
if (info == null) if (info == null)
{
instance = null;
return null; return null;
currentObject = info.GetValue(currentObject); }
instance = info.GetValue(instance);
} }
//Set the property to the value // Set the property to the value
return currentObject.GetType() PropertyInfo output =
instance.GetType()
#if SIMPLSHARP #if SIMPLSHARP
.GetCType() .GetCType()
#endif #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;
} }
/// <summary> /// <summary>
@@ -253,35 +253,23 @@ namespace ICD.Common.Utils.Extensions
/// <param name="value"></param> /// <param name="value"></param>
/// <param name="path"></param> /// <param name="path"></param>
/// <returns>true if property get was successful, false if the property was not found</returns> /// <returns>true if property get was successful, false if the property was not found</returns>
public static bool GetProperty([NotNull] this object extends, [CanBeNull] out object value, [NotNull] params string[] path) public static bool GetProperty<T>([NotNull] this object extends, [CanBeNull] out T value, [NotNull] params string[] path)
{ {
if (extends == null) if (extends == null)
throw new ArgumentNullException("extends"); throw new ArgumentNullException("extends");
if (path == null) if (path == null)
throw new ArgumentNullException("path"); throw new ArgumentNullException("path");
value = null; value = default(T);
object currentObject = extends; object instance;
PropertyInfo property = extends.GetPropertyInfo(out instance, path);
//Grab property values if (property == null)
foreach (string node in path) return false;
{
PropertyInfo info =
currentObject.GetType()
#if SIMPLSHARP
.GetCType()
#endif
.GetProperty(node);
if (info == null) value = (T)property.GetValue(instance);
return false;
currentObject = info.GetValue(currentObject);
}
//set the last value and return
value = currentObject;
return true; return true;
} }
@@ -291,7 +279,7 @@ namespace ICD.Common.Utils.Extensions
return CallMethod(extends, methodName, out value, new object[] { }); 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<T>([NotNull] this object extends, string methodName, [CanBeNull] out T value)
{ {
return CallMethod(extends, methodName, out value, new object[] { }); return CallMethod(extends, methodName, out value, new object[] { });
} }
@@ -302,25 +290,30 @@ namespace ICD.Common.Utils.Extensions
return CallMethod(extends, methodName, out value, parameters); 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<T>([NotNull] this object extends, string methodName, [CanBeNull] out T value, [NotNull] params object[] parameters)
{ {
if (extends == null) if (extends == null)
throw new ArgumentNullException("extends"); throw new ArgumentNullException("extends");
if (parameters == null) if (parameters == null)
throw new ArgumentNullException("parameters"); throw new ArgumentNullException("parameters");
value = false; value = default(T);
MethodInfo method = MethodInfo method =
extends.GetType() extends.GetType()
#if SIMPLSHARP #if SIMPLSHARP
.GetCType() .GetCType()
#endif #endif
.GetMethod(methodName); .GetMethod(methodName,
BindingFlags.Instance |
BindingFlags.Static |
BindingFlags.Public |
BindingFlags.NonPublic);
if (method == null) if (method == null)
return false; return false;
value = method.Invoke(extends, parameters); value = (T)method.Invoke(extends, parameters);
return true; return true;
} }
@@ -339,7 +332,7 @@ namespace ICD.Common.Utils.Extensions
return eventHandlerType == typeof(EventHandler) return eventHandlerType == typeof(EventHandler)
? typeof(EventArgs) ? typeof(EventArgs)
: eventHandlerType.GetInnerGenericTypes(typeof(EventHandler<>)) : eventHandlerType.GetInnerGenericTypes(typeof(EventHandler<>))
.First(); .Single();
} }
} }
} }