using System;
using System.Reflection;
using System.ComponentModel;
using System.Linq;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
namespace EasyDevCore.Common
{
///
/// Reflection Tools
///
public static class ReflectionHelper
{
///
/// Creates the object.
///
/// Name of the type.
/// The args.
///
public static object CreateInstance(string typeName, params object[] args) => CreateInstance(Type.GetType(typeName, true, true), args);
///
/// Creates the object.
///
///
/// The arguments.
///
public static T CreateInstance(params object[] args) => (T)CreateInstance(typeof(T), args);
///
/// Creates the object.
///
/// The type.
/// The arguments.
///
///
///
public static object CreateInstance(this Type type, params object[] args)
{
if (args.Length > 0)
{
return Activator.CreateInstance(type, args);
}
else
{
return Activator.CreateInstance(type);
}
}
///
/// Finds the types.
///
/// The search types.
/// if set to true [is class].
/// if set to true [is abstract].
/// if set to true [is interface].
/// The assembly predicate.
/// The type predicate.
///
public static IList FindTypes(Type[] searchTypes, bool? isClass = null, bool? isAbstract = null, bool? isInterface = null, Func assemblyPredicate = null, Func typePredicate = null)
{
IEnumerable assemblies = AppDomain.CurrentDomain.GetAssemblies();
if (assemblyPredicate != null) assemblies = assemblies.Where(assemblyPredicate);
IEnumerable types = assemblies.SelectMany(a => a.GetTypes());
bool multiType = searchTypes.Length > 1;
types = types.Where(t =>
{
bool ok = t.IsPublic && ((!multiType && searchTypes[0].IsAssignableFrom(t)) || (multiType && searchTypes.Any(st => st.IsAssignableFrom(t))));
if(isClass.HasValue && t.IsClass != isClass.Value) ok = false;
if(isAbstract.HasValue && t.IsAbstract != isAbstract.Value) ok = false;
if(isInterface.HasValue && t.IsInterface != isInterface.Value) ok = false;
return ok;
});
if (typePredicate != null) types = types.Where(typePredicate);
return types.ToList();
}
///
/// Finds the types.
///
///
/// if set to true [is class].
/// if set to true [is abstract].
/// if set to true [is interface].
/// The assembly predicate.
/// The type predicate.
///
public static IList FindTypes(bool? isClass = null, bool? isAbstract = null, bool? isInterface = null, Func assemblyPredicate = null, Func typePredicate = null)
{
Type[] types = new Type[1];
types[0] = typeof(T);
return FindTypes(types, isClass, isAbstract, isInterface, assemblyPredicate, typePredicate);
}
///
/// Gets the expression custom attribute.
///
/// The type of the odel type.
/// The type of the alue type.
///
/// The expression.
///
///
///
public static T GetExpressionCustomAttribute(this Expression> expression)
{
MemberExpression member = expression.Body as MemberExpression;
if (member == null)
throw new ArgumentException(string.Format("Expression '{0}' refers to a method, not a property.", expression.ToString()));
PropertyInfo propInfo = member.Member as PropertyInfo;
if (propInfo == null)
throw new ArgumentException(string.Format("Expression '{0}' refers to a field, not a property.", expression.ToString()));
var attributes = propInfo.GetCustomAttributes(typeof(T), true);
if (attributes.Length > 0)
return (T)attributes[0];
return default(T);
}
///
/// Gets the expression value.
///
/// The type of the model type.
/// The type of the value type.
/// The expression.
/// The source.
/// ValueType.
///
///
public static ValueType GetExpressionValue(this Expression> expression, ModelType source)
{
MemberExpression member = expression.Body as MemberExpression;
if (member == null)
throw new ArgumentException(string.Format("Expression '{0}' refers to a method, not a property.", expression.ToString()));
PropertyInfo propInfo = member.Member as PropertyInfo;
if (propInfo == null)
throw new ArgumentException(string.Format("Expression '{0}' refers to a field, not a property.", expression.ToString()));
if (source == null) throw new ArgumentNullException(nameof(source));
return (ValueType)source.GetPropertyValue(propInfo.Name);
}
///
/// Gets the name of the member.
///
///
/// The member expression.
///
public static string GetMemberName(Expression> memberExpression)
{
MemberExpression expressionBody = (MemberExpression)memberExpression.Body;
return expressionBody.Member.Name;
}
///
/// Gets the PropertyInfo for the TargetProperty.
///
/// The target object.
/// The target property.
/// Type of the return.
/// The param types (System.Type.EmptyTypes = no parameters).
///
public static PropertyInfo GetPropertyInfo(this object target, string targetProperty, Type returnType = null, Type[] paramTypes = null)
{
if ((returnType != null) || (paramTypes != null))
{
return target.GetType().GetProperty(targetProperty, BindingFlags.Public | BindingFlags.Instance, null, returnType, paramTypes, null);
}
else
{
return target.GetType().GetProperty(targetProperty);
}
}
///
/// Gets the property infos.
///
/// The type.
///
public static PropertyInfo[] GetPropertyInfos(this Type type)
{
return type.GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public).ToArray();
}
///
/// Gets multi PropertyInfo for the TargetProperty.
///
/// The target.
///
public static PropertyInfo[] GetPropertyInfos(this object target)
{
return GetPropertyInfos(target.GetType());
}
///
/// Gets the method info.
///
/// The target.
/// The target method.
/// The param types (System.Type.EmptyTypes = no parameters).
///
public static MethodInfo GetMethodInfo(this object target, string targetMethod, Type[] paramTypes = null)
{
if (paramTypes != null)
{
return target.GetType().GetMethod(targetMethod, BindingFlags.Public | BindingFlags.Instance, null, CallingConventions.Any, paramTypes, null);
}
else
{
return target.GetType().GetMethod(targetMethod);
}
}
///
/// Gets the method info.
///
/// The target.
/// The target method.
///
public static MethodInfo[] GetMethodInfos(this object target, string targetMethod)
{
return target.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public)
.Where((mi) => mi.Name == targetMethod).ToArray();
}
///
/// Invokes the method.
///
/// The target.
/// The target method.
/// The args.
///
public static object InvokeMethod(this T target, string targetMethod, params object[] args) where T: class
{
MethodInfo methodInfo = GetMethodInfo(target, targetMethod);
if (methodInfo == null)
return null;
return methodInfo.Invoke(target, args);
}
///
/// Invokes the method asynchronous.
///
///
///
/// The target.
/// The target method.
/// The arguments.
///
public static async Task InvokeMethodAsync(this T target, string targetMethod, params object[] args) where T : class
{
dynamic awaitable = (R)target.InvokeMethod(targetMethod, args);
await awaitable;
return awaitable.GetAwaiter().GetResult();
}
///
/// Checks the attribute exists.
///
///
/// The target.
///
public static bool CheckAttributeExists(this object target)
where T : Attribute
{
return Attribute.IsDefined(target.GetType().Assembly, typeof(T));
}
///
/// Gets the attribute.
///
///
/// The target.
///
public static T GetAttribute(this object target)
where T : Attribute
{
return (T)Attribute.GetCustomAttribute(target.GetType().Assembly, typeof(T));
}
///
/// Gets the attributes.
///
///
/// The target.
///
public static T[] GetAttributes(this object target)
where T : Attribute
{
return (T[])Attribute.GetCustomAttributes(target.GetType().Assembly, typeof(T));
}
///
/// Checks the property exists.
///
/// The target.
/// The target property.
///
public static bool CheckPropertyExist(this object target, string targetProperty)
{
if (target is System.Dynamic.ExpandoObject)
{
return ((IDictionary)target).ContainsKey(targetProperty);
}
else
{
object obj = target;
PropertyDescriptor prop;
while (true)
{
if (targetProperty.Contains("."))
{
string parentProperty = targetProperty.Substring(0, targetProperty.IndexOf("."));
prop = TypeDescriptor.GetProperties(obj)[parentProperty];
obj = prop.GetValue(obj);
targetProperty = targetProperty.Substring(parentProperty.Length + 1);
}
else
{
prop = TypeDescriptor.GetProperties(obj)[targetProperty];
break;
}
}
return (prop != null);
}
}
///
/// Gets the property values.
///
/// The target.
///
public static IDictionary GetPropertyValues(this object target)
{
Dictionary valuePairs = new Dictionary();
foreach(PropertyDescriptor prop in TypeDescriptor.GetProperties(target))
{
valuePairs.Add(prop.Name, prop.GetValue(target));
}
return valuePairs;
}
///
/// Gets the property value for the TargetProperty.
///
/// The target object.
/// The target property.
/// The property value.
public static object GetPropertyValue(this object target, string targetProperty)
{
if (target is System.Dynamic.ExpandoObject)
{
if (CheckPropertyExist(target, targetProperty))
{
return ((IDictionary)target)[targetProperty];
}
return null;
}
else
{
object obj = target;
PropertyDescriptor prop;
while (true)
{
if (targetProperty.Contains("."))
{
string parentProperty = targetProperty.Substring(0, targetProperty.IndexOf("."));
prop = TypeDescriptor.GetProperties(obj)[parentProperty];
obj = prop.GetValue(obj);
targetProperty = targetProperty.Substring(parentProperty.Length + 1);
}
else
{
prop = TypeDescriptor.GetProperties(obj)[targetProperty];
break;
}
}
return (prop == null) ? null : prop.GetValue(obj);
}
}
///
/// Gets the indexer value.
///
/// The target.
/// The index value.
/// The target parent property.
///
public static object GetIndexerValue(this object target, object indexValue, string targetParentProperty = "")
{
object obj = target;
PropertyDescriptor prop;
PropertyInfo pi;
while (true)
{
if (targetParentProperty.Contains("."))
{
string parentProperty = targetParentProperty.Substring(0, targetParentProperty.IndexOf("."));
prop = TypeDescriptor.GetProperties(obj)[parentProperty];
obj = prop.GetValue(obj);
targetParentProperty = targetParentProperty.Substring(parentProperty.Length + 1);
}
else
{
pi = GetPropertyInfo(obj, "Item", null, new Type[] { indexValue.GetType() });
break;
}
}
return (pi == null) ? null : pi.GetValue(obj, new object[] { indexValue });
}
///
/// Gets the indexer value.
///
///
/// The target.
/// The index value.
/// The target parent property.
///
public static T GetIndexerValue(this object target, object indexValue, string targetParentProperty = "")
{
return (T)GetIndexerValue(target, indexValue, targetParentProperty);
}
///
/// Sets the indexer value.
///
/// The target.
/// The index value.
/// The value.
/// The target parent property.
public static void SetIndexerValue(this T target, object indexValue, object value, string targetParentProperty = "") where T: class
{
object obj = target;
PropertyDescriptor prop;
PropertyInfo pi;
while (true)
{
if (targetParentProperty.Contains("."))
{
string parentProperty = targetParentProperty.Substring(0, targetParentProperty.IndexOf("."));
prop = TypeDescriptor.GetProperties(obj)[parentProperty];
obj = prop.GetValue(obj);
targetParentProperty = targetParentProperty.Substring(parentProperty.Length + 1);
}
else
{
pi = GetPropertyInfo(obj, "Item", null, new Type[] { indexValue.GetType() });
break;
}
}
pi.SetValue(obj, value, new object[] { indexValue });
}
///
/// Gets the property value for the TargetProperty.
///
/// The type of the property.
/// The target object.
/// The target property.
/// The property value.
public static T GetPropertyValue(this object target, string targetProperty)
{
return (T)(GetPropertyValue(target, targetProperty) ?? default(T));
}
///
/// Gets the property value for the TargetProperty and convert to T, if not success uses default value.
///
/// The type of the property.
/// The target object.
/// The target property.
/// The default value.
///
/// The property value.
///
public static T GetPropertyValue(this object target, string targetProperty, T defaultValue)
{
if (CheckPropertyExist(target, targetProperty))
{
var value = GetPropertyValue(target, targetProperty);
return value == null ? defaultValue : value.ConvertTo(defaultValue);
}
else
{
return defaultValue;
}
}
///
/// Sets the property value for the TargetProperty.
///
/// The target object.
/// The target property.
/// The value to set.
public static void SetPropertyValue(this T target, string targetProperty, object value)
{
if (target == null)
throw new ArgumentNullException("target", "Target object can not be Null.");
if (target is System.Dynamic.ExpandoObject)
{
((IDictionary)target)[targetProperty] = value;
}
else
{
object obj = target;
PropertyDescriptor prop;
while (true)
{
if (targetProperty.Contains("."))
{
string parentProperty = targetProperty.Substring(0, targetProperty.IndexOf("."));
prop = TypeDescriptor.GetProperties(obj)[parentProperty];
obj = prop.GetValue(obj);
targetProperty = targetProperty.Substring(parentProperty.Length + 1);
}
else
{
prop = TypeDescriptor.GetProperties(obj)[targetProperty];
break;
}
}
if (value == null)
prop.SetValue(obj, null);
else
{
SetPropertyValue(target, prop, value);
}
}
}
///
/// Sets the property value.
///
/// The type of the model.
/// The model.
/// The property.
/// The value.
public static void SetPropertyValue(TModel model, PropertyDescriptor prop, object value)
{
if (value == null)
{
prop.SetValue(model, null);
return;
}
Type pType = prop.PropertyType.GetUnderlyingType();
Type vType = value.GetType().GetUnderlyingType();
if (pType != null && (pType.Equals(vType) || pType.FullName == "System.Object"))
{
// types match, just copy value
prop.SetValue(model, value);
}
else
{
// types don't match, try to coerce
if (pType.Equals(typeof(Guid)))
{
prop.SetValue(model, new Guid(value.ToString()));
}
else if (pType.IsEnum && vType.Equals(typeof(string)))
prop.SetValue(model, Enum.Parse(pType, value.ToString()));
else if (pType.IsEnum && vType.IsNumericType())
prop.SetValue(model, value.ConvertTo());
else
prop.SetValue(model, Convert.ChangeType(value, pType));
}
}
///
/// Invokes the generic method.
///
/// The type.
/// Type of the interface.
/// Name of the method.
/// The arguments.
///
public static object InvokeGenericStaticMethod(this Type type, Type interfaceType, string methodName, params object[] args)
{
MethodInfo mi = type.GetMethods(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).First(f => f.Name == methodName);
MethodInfo miConstructed = mi.MakeGenericMethod(interfaceType);
return miConstructed.Invoke(null, args != null && args.Length > 0 ? args : null);
}
///
/// Invokes the generic static method asynchronous.
///
/// The type.
/// Type of the interface.
/// Name of the method.
/// The arguments.
///
public static async Task InvokeGenericStaticMethodAsync(this Type type, Type interfaceType, string methodName, params object[] args)
{
MethodInfo mi = type.GetMethods(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).First(f => f.Name == methodName);
MethodInfo miConstructed = mi.MakeGenericMethod(interfaceType);
Task result = (Task)miConstructed.Invoke(null, args != null && args.Length > 0 ? args : null);
return await result;
}
///
/// Invokes the generic method.
///
/// The object.
/// Type of the interface.
/// Name of the method.
/// The arguments.
///
public static object InvokeGenericMethod(this object obj, Type interfaceType, string methodName, params object[] args)
{
MethodInfo mi = obj.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).First(f => f.Name == methodName);
MethodInfo miConstructed = mi.MakeGenericMethod(interfaceType);
return miConstructed.Invoke(obj, args != null && args.Length > 0 ? args : null);
}
///
/// Invokes the generic method asynchronous.
///
/// The object.
/// Type of the interface.
/// Name of the method.
/// The arguments.
///
public static async Task