// Copyright 2009-2022 Josh Close // This file is a part of CsvHelper and is dual licensed under MS-PL and Apache 2.0. // See LICENSE.txt for details or visit http://www.opensource.org/licenses/ms-pl.html for MS-PL and http://opensource.org/licenses/Apache-2.0 for Apache 2.0. // https://github.com/JoshClose/CsvHelper using System; using System.Reflection; using System.Linq.Expressions; using System.Runtime.CompilerServices; using System.Linq; namespace CsvHelper { /// /// Extensions to help with reflection. /// public static class ReflectionExtensions { /// /// Gets the type from the member. /// /// The member to get the type from. /// The type. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Type MemberType(this MemberInfo member) { var property = member as PropertyInfo; if (property != null) { return property.PropertyType; } var field = member as FieldInfo; if (field != null) { return field.FieldType; } throw new InvalidOperationException("Member is not a property or a field."); } /// /// Gets a member expression for the member. /// /// The member to get the expression for. /// The member expression. /// The member expression. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static MemberExpression GetMemberExpression(this MemberInfo member, Expression expression) { var property = member as PropertyInfo; if (property != null) { return Expression.Property(expression, property); } var field = member as FieldInfo; if (field != null) { return Expression.Field(expression, field); } throw new InvalidOperationException("Member is not a property or a field."); } /// /// Gets a value indicating if the given type is anonymous. /// True for anonymous, otherwise false. /// /// The type. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsAnonymous(this Type type) { if (type == null) { throw new ArgumentNullException(nameof(type)); } // https://stackoverflow.com/a/2483054/68499 var isAnonymous = Attribute.IsDefined(type, typeof(CompilerGeneratedAttribute), false) && type.IsGenericType && type.Name.Contains("AnonymousType") && (type.Name.StartsWith("<>") || type.Name.StartsWith("VB$")) && (type.Attributes & TypeAttributes.Public) != TypeAttributes.Public; return isAnonymous; } /// /// Gets a value indicating if the given type has a parameterless constructor. /// True if it has a parameterless constructor, otherwise false. /// /// The type. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool HasParameterlessConstructor(this Type type) { return type.GetConstructor(new Type[0]) != null; } /// /// Gets a value indicating if the given type has any constructors. /// /// The type. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool HasConstructor(this Type type) { return type.GetConstructors().Length > 0; } /// /// Gets the constructor that contains the most parameters. /// /// The type. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ConstructorInfo GetConstructorWithMostParameters(this Type type) { return type.GetConstructors() .OrderByDescending(c => c.GetParameters().Length) .First(); } /// /// Gets a value indicating if the type is a user defined struct. /// True if it is a user defined struct, otherwise false. /// /// The type. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsUserDefinedStruct(this Type type) { return type.IsValueType && !type.IsPrimitive && !type.IsEnum; } /// /// Gets a string representation of the constructor. /// /// The constructor. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string GetDefinition(this ConstructorInfo constructor) { var parameters = constructor.GetParameters(); var definition = $"{constructor.Name}({string.Join(", ", parameters.Select(p => p.GetDefinition()))})"; return definition; } /// /// Gets a string representation of the parameter. /// /// The parameter. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string GetDefinition(this ParameterInfo parameter) { return $"{parameter.ParameterType.Name} {parameter.Name}"; } } }