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