// 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}";
}
}
}