init
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using RPGCoreCommon.Helpers.Exceptions;
|
||||
|
||||
namespace RPGCoreCommon.Helpers
|
||||
{
|
||||
public static class ReflectionExtensions
|
||||
{
|
||||
public const BindingFlags DefaultBindingFlags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase;
|
||||
|
||||
/// <summary>Works with any member (type, field, property, method)</summary>
|
||||
/// <returns>type of this member's value</returns>
|
||||
public static Type GetMemberValueType(this MemberInfo memberInfo)
|
||||
{
|
||||
return memberInfo switch
|
||||
{
|
||||
Type type => type,
|
||||
FieldInfo fieldInfo => fieldInfo.FieldType,
|
||||
PropertyInfo propertyInfo => propertyInfo.PropertyType,
|
||||
MethodInfo methodInfo => methodInfo.ReturnType,
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>Works with any member (type, field, property, method)</summary>
|
||||
/// <param name="memberInfo">this member</param>
|
||||
/// <param name="obj">Object to use for this reflection</param>
|
||||
/// <returns>member's value</returns>
|
||||
public static object GetMemberValue(this MemberInfo memberInfo, object obj)
|
||||
{
|
||||
return memberInfo switch
|
||||
{
|
||||
Type => obj,
|
||||
FieldInfo fi => fi.GetValue(obj),
|
||||
PropertyInfo pi => pi.GetValue(obj, null),
|
||||
MethodInfo mi => mi.Invoke(obj, null),
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>Works with any member (type, field, property, method)</summary>
|
||||
/// <param name="memberInfo">this member</param>
|
||||
/// <param name="path">path from current member with dot "." as delimiter</param>
|
||||
/// <param name="bindingFlags">Custom binding flags to use</param>
|
||||
/// <returns>TYPE of member's value from given path</returns>
|
||||
/// <exception cref="MemberNotFoundException">when member is not found</exception>
|
||||
public static Type GetMemberValueTypeByPath(this MemberInfo memberInfo, string path, BindingFlags bindingFlags = DefaultBindingFlags)
|
||||
{
|
||||
var pathParts = path.Split('.');
|
||||
var memberType = memberInfo.GetMemberValueType();
|
||||
|
||||
foreach (var pathPart in pathParts)
|
||||
{
|
||||
var member = memberType.GetMember(pathPart, bindingFlags).FirstOrDefault();
|
||||
if (member == null) throw new MemberNotFoundException(path, memberType.GetMemberValueType());
|
||||
memberType = member.GetMemberValueType();
|
||||
}
|
||||
|
||||
return memberType;
|
||||
}
|
||||
|
||||
/// <summary>This function supports all members: type, property, field, method</summary>
|
||||
/// <param name="memberInfo">Type (or any memberInfo) that will be used to get result value. When not provided memberInfo will be taken from obj type</param>
|
||||
/// <param name="obj">Object from which finding will be performed</param>
|
||||
/// <param name="path">path from current member with dot "." as delimiter</param>
|
||||
/// <param name="bindingFlags">Custom binding flags to use</param>
|
||||
/// <returns>member's value from given path</returns>
|
||||
/// <exception cref="MemberNotFoundException">When property at given path doesn't exist</exception>
|
||||
public static object GetMemberValueByPath(this MemberInfo memberInfo, object obj, string path, BindingFlags bindingFlags = DefaultBindingFlags)
|
||||
{
|
||||
var pathParts = path.Split('.');
|
||||
var memberType = memberInfo.GetMemberValueType();
|
||||
var memberObj = obj;
|
||||
|
||||
foreach (var pathPart in pathParts)
|
||||
{
|
||||
var member = memberType.GetMember(pathPart, bindingFlags).FirstOrDefault();
|
||||
if (member == null) throw new MemberNotFoundException(path, memberType.GetMemberValueType());
|
||||
memberType = member.GetMemberValueType();
|
||||
memberObj = memberType.GetMemberValue(memberObj);
|
||||
}
|
||||
|
||||
return memberObj;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="GetMemberValueByPath(MemberInfo, object, string, BindingFlags)"/>
|
||||
/// <exception cref="MemberValueWrongTypeException">When result is not desired type</exception>
|
||||
/// <typeparam name="T">Result type</typeparam>
|
||||
public static T GetMemberValueByPath<T>(this MemberInfo memberInfo, object obj, string path, BindingFlags bindingFlags = DefaultBindingFlags)
|
||||
{
|
||||
var result = GetMemberValueByPath(memberInfo, obj, path, bindingFlags);
|
||||
|
||||
if (result is T typedResult) return typedResult;
|
||||
|
||||
throw new MemberValueWrongTypeException(path, obj.GetType(), typeof(T), result.GetType());
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="GetMemberValueByPath(MemberInfo, object, string, BindingFlags)"/>
|
||||
public static object GetMemberValueByPath(object obj, string path, BindingFlags bindingFlags = DefaultBindingFlags)
|
||||
{
|
||||
return GetMemberValueByPath(obj.GetType(), obj, path, bindingFlags);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to find specific generic type in currently implementation.
|
||||
/// </summary>
|
||||
/// <param name="type">This type</param>
|
||||
/// <param name="genericTypeDefinition">Generic type to find</param>
|
||||
/// <returns>Found generic type with parameters</returns>
|
||||
/// <exception cref="Exception">Generic type to find isn't generic.</exception>
|
||||
public static Type FindGenericDefinitionType(this Type type, Type genericTypeDefinition)
|
||||
{
|
||||
if (!genericTypeDefinition.IsGenericTypeDefinition) throw new Exception("The generic argument must be a generic type definition.");
|
||||
|
||||
var tempType = type;
|
||||
while (tempType != null && tempType != typeof(object))
|
||||
{
|
||||
if (tempType.IsGenericType && tempType.GetGenericTypeDefinition() == genericTypeDefinition) return tempType;
|
||||
tempType = tempType.BaseType;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if specific generic type in currently implementation has type as argument at index.
|
||||
/// </summary>
|
||||
/// <param name="type">this type</param>
|
||||
/// <param name="genericTypeDefinition">Generic type to find</param>
|
||||
/// <param name="argIndex">index to check</param>
|
||||
/// <param name="argType">type in generic implementation</param>
|
||||
/// <returns></returns>
|
||||
public static bool IsArgTypeInGenericDefinitionType(this Type type, Type genericTypeDefinition, int argIndex, Type argType)
|
||||
{
|
||||
return type.FindGenericDefinitionType(genericTypeDefinition).GenericTypeArguments.ElementAtOrDefault(argIndex) == argType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if this member has public read accessor.
|
||||
/// </summary>
|
||||
/// <param name="memberInfo">this member</param>
|
||||
/// <returns>TRUE if member exists and is public</returns>
|
||||
public static bool IsMemberReadPublic(this MemberInfo memberInfo)
|
||||
{
|
||||
return memberInfo switch
|
||||
{
|
||||
Type type => type.IsPublic,
|
||||
PropertyInfo pi => pi.GetGetMethod() != null,
|
||||
MethodInfo mi => mi.IsPublic,
|
||||
FieldInfo fi => fi.IsPublic,
|
||||
_ => false
|
||||
};
|
||||
}
|
||||
|
||||
public static IEnumerable<Type> GetAllTypes(this Type forType, bool withObject = false)
|
||||
{
|
||||
var tempType = forType;
|
||||
while (tempType is not null)
|
||||
{
|
||||
yield return tempType;
|
||||
tempType = tempType.BaseType;
|
||||
if (!withObject && tempType == typeof(object)) yield break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user