Type/MemberInfo extension parity

Also resolves #25
This commit is contained in:
Oliver Booth 2021-01-18 16:55:43 +00:00
parent f980ade3a8
commit 28f46ecc8d
4 changed files with 299 additions and 123 deletions

View File

@ -0,0 +1,11 @@
using System;
namespace X10D
{
internal static class ExceptionMessages
{
public static readonly string TypeDoesNotInheritAttribute = $"{{0}} does not inherit {typeof(Attribute)}";
public static readonly string TypeIsNotClass = $"{{0}} is not a class";
public static readonly string TypeIsNotInterface = $"{{0}} is not an interface";
}
}

View File

@ -1,123 +0,0 @@
using System;
using System.ComponentModel;
using System.Reflection;
namespace X10D
{
/// <summary>
/// Extension methods for various reflection types.
/// </summary>
public static class ReflectionExtensions
{
/// <summary>
/// Gets the value set in this member's annotated <see cref="DefaultValueAttribute" />, or
/// <see langword="default" /> if none exists.
/// </summary>
/// <param name="member">The member.</param>
/// <returns>
/// Returns an <see cref="object" /> representing the value stored in this member's
/// <see cref="DefaultValueAttribute" />.
/// </returns>
/// <exception cref="ArgumentNullException"><paramref name="member" /> is <see langword="null" />.</exception>
public static object GetDefaultValue(this MemberInfo member)
{
if (member is null)
{
throw new ArgumentNullException(nameof(member));
}
if (!(member.GetCustomAttribute<DefaultValueAttribute>() is { } attribute))
{
return default;
}
return attribute.Value;
}
/// <summary>
/// Gets the value set in this member's annotated <see cref="DefaultValueAttribute" />, or
/// <see langword="default" /> if none exists.
/// </summary>
/// <typeparam name="T">The type to which the value should cast.</typeparam>
/// <param name="member">The member.</param>
/// <returns>
/// Returns an instance of <typeparamref name="T" /> representing the value stored in this member's
/// <see cref="DefaultValueAttribute" />.
/// </returns>
/// <exception cref="ArgumentNullException"><paramref name="member" /> is <see langword="null" />.</exception>
public static T GetDefaultValue<T>(this MemberInfo member)
{
if (member is null)
{
throw new ArgumentNullException(nameof(member));
}
return (T)member.GetDefaultValue();
}
/// <summary>
/// Gets the value set in this member's annotated <see cref="DescriptionAttribute" />, or
/// <see langword="null" /> if none exists.
/// </summary>
/// <param name="member">The member.</param>
/// <returns>
/// Returns a string representing the value stored in this member's
/// <see cref="DescriptionAttribute" />.
/// </returns>
/// <exception cref="ArgumentNullException"><paramref name="member" /> is <see langword="null" />.</exception>
public static string GetDescription(this MemberInfo member)
{
if (member is null)
{
throw new ArgumentNullException(nameof(member));
}
if (!(member.GetCustomAttribute<DescriptionAttribute>() is { } attribute))
{
return null;
}
return attribute.Description;
}
/// <summary>
/// Retrieves a custom attribute of a specified type that is applied to the specified member, and passes it
/// to a selector delegate in order to select one or more the members in the attribute.
/// </summary>
/// <typeparam name="TAttribute">The attribute type.</typeparam>
/// <typeparam name="TReturn">The return type of the <paramref name="selector" /> delegate.</typeparam>
/// <param name="member">The member.</param>
/// <param name="selector">The selector delegate.</param>
/// <returns>
/// Returns an instance of <typeparamref name="TReturn" /> as provided from
/// <paramref name="selector" />.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="member" /> is <see langword="null" />
/// -or-
/// <paramref name="selector" /> is <see langword="null" />.
/// </exception>
public static TReturn SelectFromCustomAttribute<TAttribute, TReturn>(
this MemberInfo member,
Func<TAttribute, TReturn> selector)
where TAttribute : Attribute
{
if (member is null)
{
throw new ArgumentNullException(nameof(member));
}
if (selector is null)
{
throw new ArgumentNullException(nameof(selector));
}
if (!(member.GetCustomAttribute<TAttribute>() is { } attribute))
{
return default;
}
return selector(attribute);
}
}
}

View File

@ -0,0 +1,98 @@
using System;
using System.Globalization;
using System.Reflection;
namespace X10D.ReflectionExtensions
{
/// <summary>
/// Extension methods for <see cref="MemberInfo" />.
/// </summary>
public static class MemberInfoExtensions
{
/// <summary>
/// Returns a value indicating whether or not the current member has been decorated with a specified attribute.
/// </summary>
/// <param name="member">The member attributes to check.</param>
/// <typeparam name="T">The attribute type.</typeparam>
/// <returns>
/// <see langword="true" /> if the current member has been decorated with a specified attribute, or
/// <see langword="false" /> otherwise.
/// </returns>
/// <exception cref="ArgumentNullException"><paramref name="member" /> is <see langword="null" />.</exception>
public static bool HasCustomAttribute<T>(this MemberInfo member)
where T : Attribute
{
if (member is null)
{
throw new ArgumentNullException(nameof(member));
}
return member.HasCustomAttribute(typeof(T));
}
/// <summary>
/// Returns a value indicating whether or not the current member has been decorated with a specified attribute.
/// </summary>
/// <param name="member">The member attributes to check.</param>
/// <param name="attribute">The attribute type.</param>
/// <returns>
/// <see langword="true" /> if the current member has been decorated with a specified attribute, or
/// <see langword="false" /> otherwise.
/// </returns>
/// <exception cref="ArgumentNullException"><paramref name="member" /> is <see langword="null" />.</exception>
public static bool HasCustomAttribute(this MemberInfo member, Type attribute)
{
if (member is null)
{
throw new ArgumentNullException(nameof(member));
}
if (attribute is null)
{
throw new ArgumentNullException(nameof(attribute));
}
if (!attribute.Inherits<Attribute>())
{
throw new ArgumentException(
string.Format(CultureInfo.CurrentCulture, ExceptionMessages.TypeDoesNotInheritAttribute, attribute),
nameof(attribute));
}
return member.GetCustomAttribute(attribute) is not null;
}
/// <summary>
/// Retrieves a custom attribute that is decorated by the current member, and projects it into to a new form.
/// </summary>
/// <typeparam name="TAttribute">The attribute type.</typeparam>
/// <typeparam name="TReturn">The return type of the <paramref name="selector" /> delegate.</typeparam>
/// <param name="type">The member.</param>
/// <param name="selector">A transform function to apply to the attribute.</param>
/// <returns>
/// An instance of <typeparamref name="TReturn" /> as provided from <paramref name="selector" />.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="type" /> is <see langword="null" />
/// -or-
/// <paramref name="selector" /> is <see langword="null" />.
/// </exception>
public static TReturn? SelectFromCustomAttribute<TAttribute, TReturn>(this MemberInfo type, Func<TAttribute, TReturn> selector)
where TAttribute : Attribute
{
if (type is null)
{
throw new ArgumentNullException(nameof(type));
}
if (selector is null)
{
throw new ArgumentNullException(nameof(selector));
}
return type.GetCustomAttribute<TAttribute>() is { } attribute
? selector(attribute)
: default;
}
}
}

View File

@ -0,0 +1,190 @@
using System;
using System.Globalization;
using System.Reflection;
namespace X10D.ReflectionExtensions
{
/// <summary>
/// Extension methods for <see cref="Type" />.
/// </summary>
public static class TypeExtensions
{
/// <summary>
/// Returns a value indicating whether or not the current type has been decorated with a specified attribute.
/// </summary>
/// <param name="type">The type whose attributes to check.</param>
/// <typeparam name="T">The attribute type.</typeparam>
/// <returns>
/// <see langword="true" /> if the current type has been decorated with a specified attribute, or
/// <see langword="false" /> otherwise.
/// </returns>
/// <exception cref="ArgumentNullException"><paramref name="type" /> is <see langword="null" />.</exception>
public static bool HasCustomAttribute<T>(this Type type)
where T : Attribute
{
if (type is null)
{
throw new ArgumentNullException(nameof(type));
}
return type.HasCustomAttribute(typeof(T));
}
/// <summary>
/// Returns a value indicating whether or not the current type has been decorated with a specified attribute.
/// </summary>
/// <param name="type">The type whose attributes to check.</param>
/// <param name="attribute">The attribute type.</param>
/// <returns>
/// <see langword="true" /> if the current type has been decorated with a specified attribute, or
/// <see langword="false" /> otherwise.
/// </returns>
/// <exception cref="ArgumentNullException"><paramref name="type" /> is <see langword="null" />.</exception>
public static bool HasCustomAttribute(this Type type, Type attribute)
{
if (type is null)
{
throw new ArgumentNullException(nameof(type));
}
if (attribute is null)
{
throw new ArgumentNullException(nameof(attribute));
}
if (!attribute.Inherits<Attribute>())
{
throw new ArgumentException(
string.Format(CultureInfo.CurrentCulture, ExceptionMessages.TypeDoesNotInheritAttribute, attribute),
nameof(attribute));
}
return type.GetCustomAttribute(attribute) is not null;
}
/// <summary>
/// Returns a value indicating whether the current type implements a specified interface.
/// </summary>
/// <param name="value">The type whose interface list to check.</param>
/// <typeparam name="T">The interface type.</typeparam>
/// <returns><see langword="true" /> if the current exists on the type, or <see langword="false" /> otherwise.</returns>
public static bool Implements<T>(this Type value)
{
return value.Implements(typeof(T));
}
/// <summary>
/// Returns a value indicating whether the current type implements a specified interface.
/// </summary>
/// <param name="value">The type whose interface list to check.</param>
/// <param name="interfaceType">The interface type.</param>
/// <returns><see langword="true" /> if the current exists on the type, or <see langword="false" /> otherwise.</returns>
public static bool Implements(this Type value, Type interfaceType)
{
if (value is null)
{
throw new ArgumentNullException(nameof(value));
}
if (interfaceType is null)
{
throw new ArgumentNullException(nameof(interfaceType));
}
if (!interfaceType.IsInterface)
{
throw new ArgumentException(
string.Format(CultureInfo.CurrentCulture, ExceptionMessages.TypeIsNotInterface, interfaceType),
nameof(interfaceType));
}
return Array.IndexOf(value.GetInterfaces(), interfaceType) >= 0;
}
/// <summary>
/// Returns a value indicating whether the current type inherits a specified type.
/// </summary>
/// <param name="value">The type whose interface list to check.</param>
/// <typeparam name="T">The base type.</typeparam>
/// <returns>
/// <see langword="true" /> if the current type inherits <typeparamref name="T" />, or <see langword="false" />
/// otherwise.
/// </returns>
public static bool Inherits<T>(this Type value)
where T : class
{
return value.Inherits(typeof(T));
}
/// <summary>
/// Returns a value indicating whether the current type inherits a specified type.
/// </summary>
/// <param name="value">The type whose interface list to check.</param>
/// <param name="type">The base type.</param>
/// <returns>
/// <see langword="true" /> if the current type inherits <paramref name="type" />, or <see langword="false" />
/// otherwise.
/// </returns>
public static bool Inherits(this Type value, Type type)
{
if (value is null)
{
throw new ArgumentNullException(nameof(value));
}
if (type is null)
{
throw new ArgumentNullException(nameof(type));
}
if (!value.IsClass)
{
throw new ArgumentException(
string.Format(CultureInfo.CurrentCulture, ExceptionMessages.TypeIsNotClass, value),
nameof(value));
}
if (!type.IsClass)
{
throw new ArgumentException(
string.Format(CultureInfo.CurrentCulture, ExceptionMessages.TypeIsNotClass, type),
nameof(type));
}
return value.IsSubclassOf(type);
}
/// <summary>
/// Retrieves a custom attribute that is decorated by the current type, and projects it into to a new form.
/// </summary>
/// <typeparam name="TAttribute">The attribute type.</typeparam>
/// <typeparam name="TReturn">The return type of the <paramref name="selector" /> delegate.</typeparam>
/// <param name="type">The type.</param>
/// <param name="selector">A transform function to apply to the attribute.</param>
/// <returns>
/// An instance of <typeparamref name="TReturn" /> as provided from <paramref name="selector" />.
/// </returns>
/// <exception cref="ArgumentNullException">
/// <paramref name="type" /> is <see langword="null" />
/// -or-
/// <paramref name="selector" /> is <see langword="null" />.
/// </exception>
public static TReturn? SelectFromCustomAttribute<TAttribute, TReturn>(this Type type, Func<TAttribute, TReturn> selector)
where TAttribute : Attribute
{
if (type is null)
{
throw new ArgumentNullException(nameof(type));
}
if (selector is null)
{
throw new ArgumentNullException(nameof(selector));
}
return type.GetCustomAttribute<TAttribute>() is { } attribute
? selector(attribute)
: default;
}
}
}