351 lines
11 KiB
C#
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
|
|
}
|
|
}
|