JD2022-TU1/main/tools/framework/JD.Kernel/Classes/ValueMemberInfo.cs

351 lines
11 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using JD.Kernel.StaticHelpers;
namespace JD.Kernel.Classes
{
/// <summary>
/// A class that wraps a <see cref="System.Reflection.FieldInfo"/> or a <see cref="System.Reflection.PropertyInfo"/> seamlessly.
/// </summary>
public class ValueMemberInfo
{
#region Variables
private readonly MemberInfo m_memberInfo;
private Attribute[] m_allAttributes;
private Attribute[] m_ownAttributes;
#endregion
#region Constructor
/// <summary>
/// Constructor.
/// </summary>
/// <param name="memberInfo"></param>
public ValueMemberInfo(MemberInfo memberInfo)
{
Throw.IfNull(memberInfo, "memberInfo");
Throw.InvalidArgumentIf(!(memberInfo is FieldInfo || memberInfo is PropertyInfo), "memberInfo must be either a FieldInfo or a PropertyInfo.", "memberInfo");
m_memberInfo = memberInfo;
}
#endregion
#region Properties
/// <summary>
/// Inner Member Info.
/// </summary>
public MemberInfo InnerMemberInfo
{
get
{
return m_memberInfo;
}
}
/// <summary>
/// Name.
/// </summary>
public string Name
{
get
{
return m_memberInfo.Name;
}
}
/// <summary>
/// Whether the member can be read.
/// </summary>
public bool CanRead
{
get { return !IsWriteOnly; }
}
/// <summary>
/// Whether the member can be written to.
/// </summary>
public bool CanWrite
{
get { return !IsReadOnly; }
}
/// <summary>
/// Whether the member info is read-only.
/// </summary>
public bool IsReadOnly
{
get
{
return m_memberInfo is FieldInfo ? ((FieldInfo)m_memberInfo).IsInitOnly : !((PropertyInfo)m_memberInfo).CanWrite;
}
}
/// <summary>
/// Whether the member info is write-only.
/// </summary>
public bool IsWriteOnly
{
get
{
return m_memberInfo is FieldInfo ? false : !((PropertyInfo)m_memberInfo).CanRead;
}
}
/// <summary>
/// Type of the member info value.
/// </summary>
public Type ValueType
{
get
{
return m_memberInfo is FieldInfo ? ((FieldInfo)m_memberInfo).FieldType : ((PropertyInfo)m_memberInfo).PropertyType;
}
}
/// <summary>
/// Custom attribtues decorating the member info.
/// </summary>
public Attribute[] AllAttributes
{
get
{
if (m_allAttributes == null)
{
m_allAttributes = Attribute.GetCustomAttributes(InnerMemberInfo, true) ?? new Attribute[] { };
}
return m_allAttributes;
}
}
/// <summary>
/// Custom attribtues decorating the member info.
/// </summary>
public Attribute[] OwnAttributes
{
get
{
if (m_ownAttributes == null)
{
m_ownAttributes = Attribute.GetCustomAttributes(InnerMemberInfo, false) ?? new Attribute[] { };
}
return m_ownAttributes;
}
}
#endregion
#region Methods
/// <summary>
/// Sets the given <paramref name="value"/> for the given <paramref name="instance"/>.
/// </summary>
/// <param name="instance"></param>
/// <param name="value"></param>
public void SetValue(object instance, object value)
{
Throw.IfNull(instance, "instance");
Throw.InvalidOperationIf(IsReadOnly, "Cannot set the value for a read-only member info.");
if (value is IConvertible)
{
var targetType = Nullable.GetUnderlyingType(ValueType) ?? ValueType;
value = Convert.ChangeType(value, targetType);
}
if (m_memberInfo is FieldInfo)
{
((FieldInfo)m_memberInfo).SetValue(instance, value);
}
else
{
System.Diagnostics.Debug.Assert(m_memberInfo is PropertyInfo);
((PropertyInfo)m_memberInfo).SetValue(instance, value, null);
}
}
/// <summary>
/// Gets the value of the member for the given <paramref name="instance"/>.
/// </summary>
/// <param name="instance"></param>
public object GetValue(object instance)
{
Throw.IfNull(instance, "instance");
if (m_memberInfo is FieldInfo)
{
return ((FieldInfo)m_memberInfo).GetValue(instance);
}
System.Diagnostics.Debug.Assert(m_memberInfo is PropertyInfo);
return ((PropertyInfo)m_memberInfo).GetValue(instance, null);
}
/// <summary>
/// Gets the custom attributes of the type <typeparamref name="TAttribute"/>.
/// </summary>
/// <typeparam name="TAttribute"></typeparam>
/// <param name="inherit"></param>
/// <returns></returns>
public IEnumerable<TAttribute> GetAttributes<TAttribute>(bool inherit)
{
return GetAttributes(inherit).OfType<TAttribute>();
}
/// <summary>
/// Gets the first attribute implementing or of type TAttribute.
/// </summary>
/// <typeparam name="TAttribute"></typeparam>
/// <returns></returns>
public TAttribute GetAttribute<TAttribute>()
{
return AllAttributes.OfType<TAttribute>().FirstOrDefault();
}
/// <summary>
/// Gets the first attribute implementing or of type TAttribute.
/// </summary>
/// <typeparam name="TAttribute"></typeparam>
/// <returns></returns>
public TAttribute GetAttribute<TAttribute>(bool inherited)
{
return GetAttributes<TAttribute>(inherited).FirstOrDefault();
}
/// <summary>
/// Gets all the attributes.
/// </summary>
/// <param name="inherited"></param>
/// <returns></returns>
public Attribute[] GetAttributes(bool inherited)
{
return inherited ? AllAttributes : OwnAttributes;
}
/// <summary>
/// Gets the value member for the given <paramref name="type"/> with the given <paramref name="name"/>.
/// </summary>
/// <param name="type"></param>
/// <param name="name"></param>
/// <param name="inherited"></param>
/// <returns></returns>
public static ValueMemberInfo GetValueMember(Type type, string name, bool inherited)
{
// Lazy implementation
foreach (ValueMemberInfo valueMemberInfo in GetValueMembers(type, inherited))
{
if (string.Equals(valueMemberInfo.Name, name))
{
return valueMemberInfo;
}
}
return null;
}
/// <summary>
/// Gets the value members for the given <paramref name="type"/>.
/// </summary>
/// <param name="type"></param>
/// <param name="inherited"></param>
/// <returns></returns>
public static IEnumerable<ValueMemberInfo> GetValueMembers(Type type, bool inherited)
{
Throw.IfNull(type, "type");
foreach (FieldInfo fieldInfo in GetFields(type, inherited))
{
yield return new ValueMemberInfo(fieldInfo);
}
foreach (PropertyInfo propertyInfo in GetProperties(type, inherited))
{
yield return new ValueMemberInfo(propertyInfo);
}
}
/// <summary>
/// Gets the field infos for the given <paramref name="type"/>
/// </summary>
/// <param name="type"></param>
/// <param name="inherited"></param>
/// <returns></returns>
private static IEnumerable<FieldInfo> GetFields(Type type, bool inherited)
{
Throw.IfNull(type, "type");
foreach (FieldInfo fieldInfo in type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly))
{
yield return fieldInfo;
}
if (inherited)
{
if (type.BaseType != typeof(object) && type.BaseType != null)
{
foreach (FieldInfo fieldInfo in GetFields(type.BaseType, inherited))
{
yield return fieldInfo;
}
}
}
}
private static IEnumerable<PropertyInfo> GetProperties(Type type, bool inherited)
{
Throw.IfNull(type, "type");
HashSet<string> alreadyReturnedVirtualMethodNames = null;
if (inherited)
{
alreadyReturnedVirtualMethodNames = new HashSet<string>();
}
foreach (PropertyInfo propertyInfo in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly))
{
if (inherited && IsAbstractVirtualOrOverrideOrHidden(propertyInfo))
{
alreadyReturnedVirtualMethodNames.Add(propertyInfo.Name);
}
yield return propertyInfo;
}
if (inherited)
{
if (type.BaseType != typeof(object) && type.BaseType != null)
{
foreach (PropertyInfo propertyInfo in GetProperties(type.BaseType, inherited))
{
if (IsAbstractVirtualOrOverrideOrHidden(propertyInfo))
{
if (!alreadyReturnedVirtualMethodNames.Add(propertyInfo.Name))
{
continue;
}
}
yield return propertyInfo;
}
}
}
}
private static bool IsAbstractVirtualOrOverrideOrHidden(PropertyInfo property)
{
return IsAbstractVirtualOrOverrideOrHidden(property.GetGetMethod(true)) || IsAbstractVirtualOrOverrideOrHidden(property.GetSetMethod(true));
}
private static bool IsAbstractVirtualOrOverrideOrHidden(MethodInfo method)
{
return method != null && (method.IsAbstract || method.IsVirtual || method.IsHideBySig);
}
#endregion
}
}