|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
namespace Microsoft.Extensions.Validation;
internal static class TypeExtensions
{
/// <summary>
/// Determines whether the specified type is an enumerable type.
/// </summary>
/// <param name="type">The type to check.</param>
/// <returns><see langword="true"/> if the type is enumerable; otherwise, <see langword="false"/>.</returns>
public static bool IsEnumerable(this Type type)
{
// Check if type itself is an IEnumerable
if (type.IsGenericType &&
(type.GetGenericTypeDefinition() == typeof(IEnumerable<>) ||
type.GetGenericTypeDefinition() == typeof(ICollection<>) ||
type.GetGenericTypeDefinition() == typeof(List<>) ||
type.GetGenericTypeDefinition() == typeof(IList<>)))
{
return true;
}
// Or an array
if (type.IsArray)
{
return true;
}
// Then evaluate if it implements IEnumerable and is not a string
if (typeof(IEnumerable).IsAssignableFrom(type) &&
type != typeof(string))
{
return true;
}
return false;
}
/// <summary>
/// Tries to get the <see cref="RequiredAttribute"/> from the specified array of validation attributes.
/// </summary>
/// <param name="attributes">The array of <see cref="ValidationAttribute"/> to search.</param>
/// <param name="requiredAttribute">The found <see cref="RequiredAttribute"/> if available, otherwise null.</param>
/// <returns><see langword="true"/> if a <see cref="RequiredAttribute"/> is found; otherwise, <see langword="false"/>.</returns>
public static bool TryGetRequiredAttribute(this ValidationAttribute[] attributes, [NotNullWhen(true)] out RequiredAttribute? requiredAttribute)
{
foreach (var attribute in attributes)
{
if (attribute is RequiredAttribute requiredAttr)
{
requiredAttribute = requiredAttr;
return true;
}
}
requiredAttribute = null;
return false;
}
/// <summary>
/// Determines whether the specified type implements the given interface.
/// </summary>
/// <param name="type">The type to check.</param>
/// <param name="interfaceType">The interface type to check for.</param>
/// <returns>True if the type implements the specified interface; otherwise, false.</returns>
public static bool ImplementsInterface(this Type type, Type interfaceType)
{
ArgumentNullException.ThrowIfNull(type);
ArgumentNullException.ThrowIfNull(interfaceType);
// Check if interfaceType is actually an interface
if (!interfaceType.IsInterface)
{
throw new ArgumentException($"Type {interfaceType.FullName} is not an interface.", nameof(interfaceType));
}
return interfaceType.IsAssignableFrom(type);
}
}
|