using System; using System.Reflection; using System.Reflection.Emit; namespace Vanara.Extensions { /// Extensions related to System.Reflection public static class ReflectionExtensions { /// Gets a named property value from an object. /// The expected type of the property to be returned. /// The object from which to retrieve the property. /// Name of the property. /// The default value to return in the instance that the property is not found. /// The property value, if found, or the if not. public static T GetPropertyValue(this object obj, string propertyName, T defaultValue = default(T)) { var prop = obj.GetType().GetProperty(propertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, typeof(T), Type.EmptyTypes, null); if (prop == null) return defaultValue; var val = prop.GetValue(obj, null); if (val == null) return defaultValue; return (T)val; } /// Invokes a named method on a created instance of a type with parameters. /// The expected type of the method's return value. /// The type to be instantiated and then used to invoke the method. This method assumes the type has a default public constructor. /// Name of the method. /// The arguments to provide to the method invocation. /// The value returned from the method. public static T InvokeMethod(this Type type, string methodName, params object[] args) { var o = Activator.CreateInstance(type); return InvokeMethod(o, methodName, args); } /// Invokes a named method on a created instance of a type with parameters. /// The expected type of the method's return value. /// The type to be instantiated and then used to invoke the method. /// The arguments to supply to the constructor. /// Name of the method. /// The arguments to provide to the method invocation. /// The value returned from the method. public static T InvokeMethod(this Type type, object[] instArgs, string methodName, params object[] args) { var o = Activator.CreateInstance(type, instArgs); return InvokeMethod(o, methodName, args); } /// Invokes a named method on an object with parameters and no return value. /// The object on which to invoke the method. /// Name of the method. /// The arguments to provide to the method invocation. public static void InvokeMethod(this object obj, string methodName, params object[] args) { var argTypes = args == null || args.Length == 0 ? Type.EmptyTypes : Array.ConvertAll(args, o => o?.GetType() ?? typeof(object)); InvokeMethod(obj, methodName, argTypes, args); } /// Invokes a named method on an object with parameters and no return value. /// The expected type of the method's return value. /// The object on which to invoke the method. /// Name of the method. /// The arguments to provide to the method invocation. /// The value returned from the method. public static T InvokeMethod(this object obj, string methodName, params object[] args) { var argTypes = args == null || args.Length == 0 ? Type.EmptyTypes : Array.ConvertAll(args, o => o?.GetType() ?? typeof(object)); return InvokeMethod(obj, methodName, argTypes, args); } /// Invokes a named method on an object with parameters and no return value. /// The object on which to invoke the method. /// Name of the method. /// The argument types. /// The arguments to provide to the method invocation. public static void InvokeMethod(this object obj, string methodName, Type[] argTypes, object[] args) { var mi = obj?.GetType().GetMethod(methodName, argTypes); if (mi == null) throw new ArgumentException(@"Method not found", nameof(methodName)); mi.Invoke(obj, args); } /// Invokes a named method on an object with parameters and no return value. /// The expected type of the method's return value. /// The object on which to invoke the method. /// Name of the method. /// The argument types. /// The arguments to provide to the method invocation. /// The value returned from the method. public static T InvokeMethod(this object obj, string methodName, Type[] argTypes, object[] args) { var mi = obj?.GetType().GetMethod(methodName, argTypes); if (mi == null) throw new ArgumentException(@"Method not found", nameof(methodName)); var tt = typeof(T); if (tt != typeof(object) && mi.ReturnType != tt && !mi.ReturnType.IsSubclassOf(tt)) throw new ArgumentException(@"Return type mismatch", nameof(T)); return (T)mi.Invoke(obj, args); } #if !(NETSTANDARD2_0) /// Invokes a method from a derived base class. /// The instance from the derived class for the method to invoke. /// The target object. /// The arguments. /// The value returned from the method. public static object InvokeNotOverride(this MethodInfo methodInfo, object targetObject, params object[] arguments) { var parameters = methodInfo.GetParameters(); if (parameters.Length != arguments.Length) throw new Exception("Arguments count doesn't match"); Type returnType = null; if (methodInfo.ReturnType != typeof(void)) returnType = methodInfo.ReturnType; var type = targetObject.GetType(); var dynamicMethod = new DynamicMethod("", returnType, new [] { type, typeof(object) }, type); var iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); // this for (var i = 0; i < parameters.Length; i++) { var parameter = parameters[i]; iLGenerator.Emit(OpCodes.Ldarg_1); // load array argument // get element at index iLGenerator.Emit(OpCodes.Ldc_I4_S, i); // specify index iLGenerator.Emit(OpCodes.Ldelem_Ref); // get element var parameterType = parameter.ParameterType; iLGenerator.Emit(OpCodes.Unbox_Any, parameterType); } iLGenerator.Emit(OpCodes.Call, methodInfo); iLGenerator.Emit(OpCodes.Ret); return dynamicMethod.Invoke(null, new [] { targetObject, arguments }); } #endif /// Loads a type from a named assembly. /// Name of the type. /// The name or path of the file that contains the manifest of the assembly. /// The reference, or null if type or assembly not found. public static Type LoadType(string typeName, string asmRef = null) { Type ret = null; Assembly asm = null; try { asm = Assembly.LoadFrom(asmRef); } catch { } if (!TryGetType(asm, typeName, ref ret)) if (!TryGetType(Assembly.GetExecutingAssembly(), typeName, ref ret)) if (!TryGetType(Assembly.GetCallingAssembly(), typeName, ref ret)) TryGetType(Assembly.GetEntryAssembly(), typeName, ref ret); return ret; } /// Tries the retrieve a reference from an assembly. /// Name of the type. /// The assembly from which to load the type. /// The reference, if found. /// true if the type was found in the assembly; otherwise, false. private static bool TryGetType(Assembly asm, string typeName, ref Type type) { if (asm == null) return false; type = asm.GetType(typeName, false, false); return type != null; } } }