NLDClient-yudde/ProjectNLD/Assets/ThirdParty/YamlDotNet/ReflectionExtensions.cs

346 lines
12 KiB
C#

// This file is part of YamlDotNet - A .NET library for YAML.
// Copyright (c) Antoine Aubry and contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace YamlDotNet
{
internal static class ReflectionExtensions
{
public static Type? BaseType(this Type type)
{
return type.GetTypeInfo().BaseType;
}
public static bool IsValueType(this Type type)
{
return type.GetTypeInfo().IsValueType;
}
public static bool IsGenericType(this Type type)
{
return type.GetTypeInfo().IsGenericType;
}
public static bool IsGenericTypeDefinition(this Type type)
{
return type.GetTypeInfo().IsGenericTypeDefinition;
}
public static Type? GetImplementationOfOpenGenericInterface(this Type type, Type openGenericType)
{
if (!openGenericType.IsGenericType || !openGenericType.IsInterface)
{
// Note we can likely relax this constraint to also allow for matching other types
throw new ArgumentException("The type must be a generic type definition and an interface", nameof(openGenericType));
}
// First check if the type itself is the open generic type
if (IsGenericDefinitionOfType(type, openGenericType))
{
return type;
}
// Then check the interfaces
return type.FindInterfaces(static (t, context) => IsGenericDefinitionOfType(t, context), openGenericType).FirstOrDefault();
static bool IsGenericDefinitionOfType(Type t, object? context)
{
return t.IsGenericType && context is Type type && t.GetGenericTypeDefinition() == type;
}
}
public static bool IsInterface(this Type type)
{
return type.GetTypeInfo().IsInterface;
}
public static bool IsEnum(this Type type)
{
return type.GetTypeInfo().IsEnum;
}
public static bool IsRequired(this MemberInfo member)
{
#if NET8_0_OR_GREATER
var result = member.GetCustomAttributes<System.Runtime.CompilerServices.RequiredMemberAttribute>().Any();
#else
var result = member.GetCustomAttributes(true).Any(x => x.GetType().FullName == "System.Runtime.CompilerServices.RequiredMemberAttribute");
#endif
return result;
}
/// <summary>
/// Determines whether the specified type has a default constructor.
/// </summary>
/// <param name="type">The type.</param>
/// <param name="allowPrivateConstructors">Whether to include private constructors</param>
/// <returns>
/// <c>true</c> if the type has a default constructor; otherwise, <c>false</c>.
/// </returns>
public static bool HasDefaultConstructor(this Type type, bool allowPrivateConstructors)
{
var bindingFlags = BindingFlags.Instance | BindingFlags.Public;
if (allowPrivateConstructors)
{
bindingFlags |= BindingFlags.NonPublic;
}
return type.IsValueType || type.GetConstructor(bindingFlags, null, Type.EmptyTypes, null) != null;
}
public static bool IsAssignableFrom(this Type type, Type source)
{
return type.IsAssignableFrom(source.GetTypeInfo());
}
public static bool IsAssignableFrom(this Type type, TypeInfo source)
{
return type.GetTypeInfo().IsAssignableFrom(source);
}
public static TypeCode GetTypeCode(this Type type)
{
var isEnum = type.IsEnum();
if (isEnum)
{
type = Enum.GetUnderlyingType(type);
}
if (type == typeof(bool))
{
return TypeCode.Boolean;
}
else if (type == typeof(char))
{
return TypeCode.Char;
}
else if (type == typeof(sbyte))
{
return TypeCode.SByte;
}
else if (type == typeof(byte))
{
return TypeCode.Byte;
}
else if (type == typeof(short))
{
return TypeCode.Int16;
}
else if (type == typeof(ushort))
{
return TypeCode.UInt16;
}
else if (type == typeof(int))
{
return TypeCode.Int32;
}
else if (type == typeof(uint))
{
return TypeCode.UInt32;
}
else if (type == typeof(long))
{
return TypeCode.Int64;
}
else if (type == typeof(ulong))
{
return TypeCode.UInt64;
}
else if (type == typeof(float))
{
return TypeCode.Single;
}
else if (type == typeof(double))
{
return TypeCode.Double;
}
else if (type == typeof(decimal))
{
return TypeCode.Decimal;
}
else if (type == typeof(DateTime))
{
return TypeCode.DateTime;
}
else if (type == typeof(string))
{
return TypeCode.String;
}
else
{
return TypeCode.Object;
}
}
public static bool IsDbNull(this object value)
{
return value?.GetType()?.FullName == "System.DBNull";
}
public static Type[] GetGenericArguments(this Type type)
{
return type.GetTypeInfo().GenericTypeArguments;
}
public static PropertyInfo? GetPublicProperty(this Type type, string name)
{
// In the case of property hiding, get the most-derived implementation.
return type
.GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public)
.FirstOrDefault(p => p.Name == name);
}
public static FieldInfo? GetPublicStaticField(this Type type, string name)
{
return type.GetRuntimeField(name);
}
private static readonly Func<PropertyInfo, bool> IsInstance = (PropertyInfo property) => !(property.GetMethod ?? property.SetMethod).IsStatic;
private static readonly Func<PropertyInfo, bool> IsInstancePublic = (PropertyInfo property) => IsInstance(property) && (property.GetMethod ?? property.SetMethod).IsPublic;
public static IEnumerable<PropertyInfo> GetProperties(this Type type, bool includeNonPublic)
{
var predicate = includeNonPublic ? IsInstance : IsInstancePublic;
return type.IsInterface()
? (new Type[] { type })
.Concat(type.GetInterfaces())
.SelectMany(i => i.GetRuntimeProperties().Where(predicate))
: type.GetRuntimeProperties().Where(predicate);
}
public static IEnumerable<PropertyInfo> GetPublicProperties(this Type type) => GetProperties(type, false);
public static IEnumerable<FieldInfo> GetPublicFields(this Type type)
{
return type.GetRuntimeFields().Where(f => !f.IsStatic && f.IsPublic);
}
public static IEnumerable<MethodInfo> GetPublicStaticMethods(this Type type)
{
return type.GetRuntimeMethods()
.Where(m => m.IsPublic && m.IsStatic);
}
public static MethodInfo GetPrivateStaticMethod(this Type type, string name)
{
return type.GetRuntimeMethods()
.FirstOrDefault(m => !m.IsPublic && m.IsStatic && m.Name.Equals(name))
?? throw new MissingMethodException($"Expected to find a method named '{name}' in '{type.FullName}'.");
}
public static MethodInfo? GetPublicStaticMethod(this Type type, string name, params Type[] parameterTypes)
{
return type.GetRuntimeMethods()
.FirstOrDefault(m =>
{
if (m.IsPublic && m.IsStatic && m.Name.Equals(name))
{
var parameters = m.GetParameters();
return parameters.Length == parameterTypes.Length
&& parameters.Zip(parameterTypes, (pi, pt) => pi.ParameterType == pt).All(r => r);
}
return false;
});
}
public static MethodInfo? GetPublicInstanceMethod(this Type type, string name)
{
return type.GetRuntimeMethods()
.FirstOrDefault(m => m.IsPublic && !m.IsStatic && m.Name.Equals(name));
}
public static MethodInfo? GetGetMethod(this PropertyInfo property, bool nonPublic)
{
var getter = property.GetMethod;
if (!nonPublic && !getter.IsPublic)
{
getter = null;
}
return getter;
}
public static MethodInfo? GetSetMethod(this PropertyInfo property)
{
return property.SetMethod;
}
public static IEnumerable<Type> GetInterfaces(this Type type)
{
return type.GetTypeInfo().ImplementedInterfaces;
}
public static bool IsInstanceOf(this Type type, object o)
{
return o.GetType() == type || o.GetType().GetTypeInfo().IsSubclassOf(type);
}
public static Attribute[] GetAllCustomAttributes<TAttribute>(this PropertyInfo member)
{
return Attribute.GetCustomAttributes(member, typeof(TAttribute), inherit: true);
}
private static readonly ConcurrentDictionary<Type, bool> TypesHaveNullContext = new();
public static bool AcceptsNull(this MemberInfo member)
{
var result = true; //default to allowing nulls, this will be set to false if there is a null context on the type
#if NET8_0_OR_GREATER
var typeHasNullContext = TypesHaveNullContext.GetOrAdd(member.DeclaringType, (Type t) =>
{
var attributes = t.GetCustomAttributes(typeof(System.Runtime.CompilerServices.NullableContextAttribute), true);
return (attributes?.Length ?? 0) > 0;
});
if (typeHasNullContext)
{
// we have a nullable context on that type, only allow null if the NullableAttribute is on the member.
var memberAttributes = member.GetCustomAttributes(typeof(System.Runtime.CompilerServices.NullableAttribute), true);
result = (memberAttributes?.Length ?? 0) > 0;
}
return result;
#else
var typeHasNullContext = TypesHaveNullContext.GetOrAdd(member.DeclaringType, (Type t) =>
{
var attributes = t.GetCustomAttributes(true);
return attributes.Any(x => x.GetType().FullName == "System.Runtime.CompilerServices.NullableContextAttribute");
});
if (typeHasNullContext)
{
var memberAttributes = member.GetCustomAttributes(true);
result = memberAttributes.Any(x => x.GetType().FullName == "System.Runtime.CompilerServices.NullableAttribute");
}
return result;
#endif
}
}
}