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();
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);
}

View File

@@ -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
/// </summary>
/// <param name="extends"></param>
/// <param name="instance"></param>
/// <param name="path"></param>
/// <returns>true if property get was successful, false if the property was not found</returns>
/// <returns></returns>
[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;
}
/// <summary>
@@ -253,35 +253,23 @@ namespace ICD.Common.Utils.Extensions
/// <param name="value"></param>
/// <param name="path"></param>
/// <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)
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<T>([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<T>([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();
}
}
}