Utilities
ReflectionUtils.cs
#region License
// Copyright (c) 2007 James Newton-King
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and astociated docameentation
// 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.
#endregion
using System;
using System.Collections.Generic;
#if !(PORTABLE || PORTABLE40 || NET35 || NET20)
using System.Numerics;
#endif
using System.Reflection;
using System.Collections;
using System.Globalization;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Text;
#if NET20
using Newtonsoft.Json.Utilities.LinqBridge;
#else
using System.Linq;
#endif
using Newtonsoft.Json.Serialization;
namespace Newtonsoft.Json.Utilities
{
#if (DOTNET || PORTABLE || PORTABLE40)
internal enum MemberTypes
{
Property = 0,
Field = 1,
Event = 2,
Method = 3,
Other = 4
}
#endif
#if PORTABLE
[Flags]
internal enum BindingFlags
{
Default = 0,
IgnoreCase = 1,
DeclaredOnly = 2,
Instance = 4,
Static = 8,
Public = 16,
NonPublic = 32,
FlattenHierarchy = 64,
InvokeMethod = 256,
CreateInstance = 512,
GetField = 1024,
SetField = 2048,
GetProperty = 4096,
SetProperty = 8192,
PutDispProperty = 16384,
ExactBinding = 65536,
PutRefDispProperty = 32768,
SuppressChangeType = 131072,
OptionalParamBinding = 262144,
IgnoreReturn = 16777216
}
#endif
internal static clast ReflectionUtils
{
public static readonly Type[] EmptyTypes;
static ReflectionUtils()
{
#if !(PORTABLE40 || PORTABLE)
EmptyTypes = Type.EmptyTypes;
#else
EmptyTypes = new Type[0];
#endif
}
public static bool IsVirtual(this PropertyInfo propertyInfo)
{
ValidationUtils.ArgumentNotNull(propertyInfo, nameof(propertyInfo));
MethodInfo m = propertyInfo.GetGetMethod();
if (m != null && m.IsVirtual)
{
return true;
}
m = propertyInfo.GetSetMethod();
if (m != null && m.IsVirtual)
{
return true;
}
return false;
}
public static MethodInfo GetBaseDefinition(this PropertyInfo propertyInfo)
{
ValidationUtils.ArgumentNotNull(propertyInfo, nameof(propertyInfo));
MethodInfo m = propertyInfo.GetGetMethod();
if (m != null)
{
return m.GetBaseDefinition();
}
m = propertyInfo.GetSetMethod();
if (m != null)
{
return m.GetBaseDefinition();
}
return null;
}
public static bool IsPublic(PropertyInfo property)
{
if (property.GetGetMethod() != null && property.GetGetMethod().IsPublic)
{
return true;
}
if (property.GetSetMethod() != null && property.GetSetMethod().IsPublic)
{
return true;
}
return false;
}
public static Type GetObjectType(object v)
{
return (v != null) ? v.GetType() : null;
}
public static string GetTypeName(Type t, FormatterastemblyStyle astemblyFormat, SerializationBinder binder)
{
string fullyQualifiedTypeName;
#if !(NET20 || NET35)
if (binder != null)
{
string astemblyName, typeName;
binder.BindToName(t, out astemblyName, out typeName);
fullyQualifiedTypeName = typeName + (astemblyName == null ? "" : ", " + astemblyName);
}
else
{
fullyQualifiedTypeName = t.astemblyQualifiedName;
}
#else
fullyQualifiedTypeName = t.astemblyQualifiedName;
#endif
switch (astemblyFormat)
{
case FormatterastemblyStyle.Simple:
return RemoveastemblyDetails(fullyQualifiedTypeName);
case FormatterastemblyStyle.Full:
return fullyQualifiedTypeName;
default:
throw new ArgumentOutOfRangeException();
}
}
private static string RemoveastemblyDetails(string fullyQualifiedTypeName)
{
StringBuilder builder = new StringBuilder();
// loop through the type name and filter out qualified astembly details from nested type names
bool writingastemblyName = false;
bool skippingastemblyDetails = false;
for (int i = 0; i < fullyQualifiedTypeName.Length; i++)
{
char current = fullyQualifiedTypeName[i];
switch (current)
{
case '[':
writingastemblyName = false;
skippingastemblyDetails = false;
builder.Append(current);
break;
case ']':
writingastemblyName = false;
skippingastemblyDetails = false;
builder.Append(current);
break;
case ',':
if (!writingastemblyName)
{
writingastemblyName = true;
builder.Append(current);
}
else
{
skippingastemblyDetails = true;
}
break;
default:
if (!skippingastemblyDetails)
{
builder.Append(current);
}
break;
}
}
return builder.ToString();
}
public static bool HasDefaultConstructor(Type t, bool nonPublic)
{
ValidationUtils.ArgumentNotNull(t, nameof(t));
if (t.IsValueType())
{
return true;
}
return (GetDefaultConstructor(t, nonPublic) != null);
}
public static ConstructorInfo GetDefaultConstructor(Type t)
{
return GetDefaultConstructor(t, false);
}
public static ConstructorInfo GetDefaultConstructor(Type t, bool nonPublic)
{
BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public;
if (nonPublic)
{
bindingFlags = bindingFlags | BindingFlags.NonPublic;
}
return t.GetConstructors(bindingFlags).SingleOrDefault(c => !c.GetParameters().Any());
}
public static bool IsNullable(Type t)
{
ValidationUtils.ArgumentNotNull(t, nameof(t));
if (t.IsValueType())
{
return IsNullableType(t);
}
return true;
}
public static bool IsNullableType(Type t)
{
ValidationUtils.ArgumentNotNull(t, nameof(t));
return (t.IsGenericType() && t.GetGenericTypeDefinition() == typeof(Nullable));
}
public static Type EnsureNotNullableType(Type t)
{
return (IsNullableType(t))
? Nullable.GetUnderlyingType(t)
: t;
}
public static bool IsGenericDefinition(Type type, Type genericInterfaceDefinition)
{
if (!type.IsGenericType())
{
return false;
}
Type t = type.GetGenericTypeDefinition();
return (t == genericInterfaceDefinition);
}
public static bool ImplementsGenericDefinition(Type type, Type genericInterfaceDefinition)
{
Type implementingType;
return ImplementsGenericDefinition(type, genericInterfaceDefinition, out implementingType);
}
public static bool ImplementsGenericDefinition(Type type, Type genericInterfaceDefinition, out Type implementingType)
{
ValidationUtils.ArgumentNotNull(type, nameof(type));
ValidationUtils.ArgumentNotNull(genericInterfaceDefinition, nameof(genericInterfaceDefinition));
if (!genericInterfaceDefinition.IsInterface() || !genericInterfaceDefinition.IsGenericTypeDefinition())
{
throw new ArgumentNullException("'{0}' is not a generic interface definition.".FormatWith(CultureInfo.InvariantCulture, genericInterfaceDefinition));
}
if (type.IsInterface())
{
if (type.IsGenericType())
{
Type interfaceDefinition = type.GetGenericTypeDefinition();
if (genericInterfaceDefinition == interfaceDefinition)
{
implementingType = type;
return true;
}
}
}
foreach (Type i in type.GetInterfaces())
{
if (i.IsGenericType())
{
Type interfaceDefinition = i.GetGenericTypeDefinition();
if (genericInterfaceDefinition == interfaceDefinition)
{
implementingType = i;
return true;
}
}
}
implementingType = null;
return false;
}
public static bool InheritsGenericDefinition(Type type, Type genericClastDefinition)
{
Type implementingType;
return InheritsGenericDefinition(type, genericClastDefinition, out implementingType);
}
public static bool InheritsGenericDefinition(Type type, Type genericClastDefinition, out Type implementingType)
{
ValidationUtils.ArgumentNotNull(type, nameof(type));
ValidationUtils.ArgumentNotNull(genericClastDefinition, nameof(genericClastDefinition));
if (!genericClastDefinition.IsClast() || !genericClastDefinition.IsGenericTypeDefinition())
{
throw new ArgumentNullException("'{0}' is not a generic clast definition.".FormatWith(CultureInfo.InvariantCulture, genericClastDefinition));
}
return InheritsGenericDefinitionInternal(type, genericClastDefinition, out implementingType);
}
private static bool InheritsGenericDefinitionInternal(Type currentType, Type genericClastDefinition, out Type implementingType)
{
if (currentType.IsGenericType())
{
Type currentGenericClastDefinition = currentType.GetGenericTypeDefinition();
if (genericClastDefinition == currentGenericClastDefinition)
{
implementingType = currentType;
return true;
}
}
if (currentType.BaseType() == null)
{
implementingType = null;
return false;
}
return InheritsGenericDefinitionInternal(currentType.BaseType(), genericClastDefinition, out implementingType);
}
///
/// Gets the type of the typed collection's items.
///
/// The type.
/// The type of the typed collection's items.
public static Type GetCollectionItemType(Type type)
{
ValidationUtils.ArgumentNotNull(type, nameof(type));
Type genericListType;
if (type.IsArray)
{
return type.GetElementType();
}
if (ImplementsGenericDefinition(type, typeof(IEnumerable), out genericListType))
{
if (genericListType.IsGenericTypeDefinition())
{
throw new Exception("Type {0} is not a collection.".FormatWith(CultureInfo.InvariantCulture, type));
}
return genericListType.GetGenericArguments()[0];
}
if (typeof(IEnumerable).IsastignableFrom(type))
{
return null;
}
throw new Exception("Type {0} is not a collection.".FormatWith(CultureInfo.InvariantCulture, type));
}
public static void GetDictionaryKeyValueTypes(Type dictionaryType, out Type keyType, out Type valueType)
{
ValidationUtils.ArgumentNotNull(dictionaryType, nameof(dictionaryType));
Type genericDictionaryType;
if (ImplementsGenericDefinition(dictionaryType, typeof(IDictionary), out genericDictionaryType))
{
if (genericDictionaryType.IsGenericTypeDefinition())
{
throw new Exception("Type {0} is not a dictionary.".FormatWith(CultureInfo.InvariantCulture, dictionaryType));
}
Type[] dictionaryGenericArguments = genericDictionaryType.GetGenericArguments();
keyType = dictionaryGenericArguments[0];
valueType = dictionaryGenericArguments[1];
return;
}
if (typeof(IDictionary).IsastignableFrom(dictionaryType))
{
keyType = null;
valueType = null;
return;
}
throw new Exception("Type {0} is not a dictionary.".FormatWith(CultureInfo.InvariantCulture, dictionaryType));
}
///
/// Gets the member's underlying type.
///
/// The member.
/// The underlying type of the member.
public static Type GetMemberUnderlyingType(MemberInfo member)
{
ValidationUtils.ArgumentNotNull(member, nameof(member));
switch (member.MemberType())
{
case MemberTypes.Field:
return ((FieldInfo)member).FieldType;
case MemberTypes.Property:
return ((PropertyInfo)member).PropertyType;
case MemberTypes.Event:
return ((EventInfo)member).EventHandlerType;
case MemberTypes.Method:
return ((MethodInfo)member).ReturnType;
default:
throw new ArgumentException("MemberInfo must be of type FieldInfo, PropertyInfo, EventInfo or MethodInfo", nameof(member));
}
}
///
/// Determines whether the member is an indexed property.
///
/// The member.
///
/// true if the member is an indexed property; otherwise, false.
///
public static bool IsIndexedProperty(MemberInfo member)
{
ValidationUtils.ArgumentNotNull(member, nameof(member));
PropertyInfo propertyInfo = member as PropertyInfo;
if (propertyInfo != null)
{
return IsIndexedProperty(propertyInfo);
}
else
{
return false;
}
}
///
/// Determines whether the property is an indexed property.
///
/// The property.
///
/// true if the property is an indexed property; otherwise, false.
///
public static bool IsIndexedProperty(PropertyInfo property)
{
ValidationUtils.ArgumentNotNull(property, nameof(property));
return (property.GetIndexParameters().Length > 0);
}
///
/// Gets the member's value on the object.
///
/// The member.
/// The target object.
/// The member's value on the object.
public static object GetMemberValue(MemberInfo member, object target)
{
ValidationUtils.ArgumentNotNull(member, nameof(member));
ValidationUtils.ArgumentNotNull(target, nameof(target));
switch (member.MemberType())
{
case MemberTypes.Field:
return ((FieldInfo)member).GetValue(target);
case MemberTypes.Property:
try
{
return ((PropertyInfo)member).GetValue(target, null);
}
catch (TargetParameterCountException e)
{
throw new ArgumentException("MemberInfo '{0}' has index parameters".FormatWith(CultureInfo.InvariantCulture, member.Name), e);
}
default:
throw new ArgumentException("MemberInfo '{0}' is not of type FieldInfo or PropertyInfo".FormatWith(CultureInfo.InvariantCulture, CultureInfo.InvariantCulture, member.Name), nameof(member));
}
}
///
/// Sets the member's value on the target object.
///
/// The member.
/// The target.
/// The value.
public static void SetMemberValue(MemberInfo member, object target, object value)
{
ValidationUtils.ArgumentNotNull(member, nameof(member));
ValidationUtils.ArgumentNotNull(target, nameof(target));
switch (member.MemberType())
{
case MemberTypes.Field:
((FieldInfo)member).SetValue(target, value);
break;
case MemberTypes.Property:
((PropertyInfo)member).SetValue(target, value, null);
break;
default:
throw new ArgumentException("MemberInfo '{0}' must be of type FieldInfo or PropertyInfo".FormatWith(CultureInfo.InvariantCulture, member.Name), nameof(member));
}
}
///
/// Determines whether the specified MemberInfo can be read.
///
/// The MemberInfo to determine whether can be read.
/// /// if set to true then allow the member to be gotten non-publicly.
///
/// true if the specified MemberInfo can be read; otherwise, false.
///
public static bool CanReadMemberValue(MemberInfo member, bool nonPublic)
{
switch (member.MemberType())
{
case MemberTypes.Field:
FieldInfo fieldInfo = (FieldInfo)member;
if (nonPublic)
{
return true;
}
else if (fieldInfo.IsPublic)
{
return true;
}
return false;
case MemberTypes.Property:
PropertyInfo propertyInfo = (PropertyInfo)member;
if (!propertyInfo.CanRead)
{
return false;
}
if (nonPublic)
{
return true;
}
return (propertyInfo.GetGetMethod(nonPublic) != null);
default:
return false;
}
}
///
/// Determines whether the specified MemberInfo can be set.
///
/// The MemberInfo to determine whether can be set.
/// if set to true then allow the member to be set non-publicly.
/// if set to true then allow the member to be set if read-only.
///
/// true if the specified MemberInfo can be set; otherwise, false.
///
public static bool CanSetMemberValue(MemberInfo member, bool nonPublic, bool canSetReadOnly)
{
switch (member.MemberType())
{
case MemberTypes.Field:
FieldInfo fieldInfo = (FieldInfo)member;
if (fieldInfo.IsLiteral)
{
return false;
}
if (fieldInfo.IsInitOnly && !canSetReadOnly)
{
return false;
}
if (nonPublic)
{
return true;
}
if (fieldInfo.IsPublic)
{
return true;
}
return false;
case MemberTypes.Property:
PropertyInfo propertyInfo = (PropertyInfo)member;
if (!propertyInfo.CanWrite)
{
return false;
}
if (nonPublic)
{
return true;
}
return (propertyInfo.GetSetMethod(nonPublic) != null);
default:
return false;
}
}
public static List GetFieldsAndProperties(Type type, BindingFlags bindingAttr)
{
List targetMembers = new List();
targetMembers.AddRange(GetFields(type, bindingAttr));
targetMembers.AddRange(GetProperties(type, bindingAttr));
// for some reason .NET returns multiple members when overriding a generic member on a base clast
// http://social.msdn.microsoft.com/Forums/en-US/b5abbfee-e292-4a64-8907-4e3f0fb90cd9/reflection-overriden-abstract-generic-properties?forum=netfxbcl
// filter members to only return the override on the topmost clast
// update: I think this is fixed in .NET 3.5 SP1 - leave this in for now...
List distinctMembers = new List(targetMembers.Count);
foreach (var groupedMember in targetMembers.GroupBy(m => m.Name))
{
int count = groupedMember.Count();
IList members = groupedMember.ToList();
if (count == 1)
{
distinctMembers.Add(members.First());
}
else
{
IList resolvedMembers = new List();
foreach (MemberInfo memberInfo in members)
{
// this is a bit hacky
// if the hiding property is hiding a base property and it is virtual
// then this ensures the derived property gets used
if (resolvedMembers.Count == 0)
{
resolvedMembers.Add(memberInfo);
}
else if (!IsOverridenGenericMember(memberInfo, bindingAttr) || memberInfo.Name == "Item")
{
resolvedMembers.Add(memberInfo);
}
}
distinctMembers.AddRange(resolvedMembers);
}
}
return distinctMembers;
}
private static bool IsOverridenGenericMember(MemberInfo memberInfo, BindingFlags bindingAttr)
{
if (memberInfo.MemberType() != MemberTypes.Property)
{
return false;
}
PropertyInfo propertyInfo = (PropertyInfo)memberInfo;
if (!IsVirtual(propertyInfo))
{
return false;
}
Type declaringType = propertyInfo.DeclaringType;
if (!declaringType.IsGenericType())
{
return false;
}
Type genericTypeDefinition = declaringType.GetGenericTypeDefinition();
if (genericTypeDefinition == null)
{
return false;
}
MemberInfo[] members = genericTypeDefinition.GetMember(propertyInfo.Name, bindingAttr);
if (members.Length == 0)
{
return false;
}
Type memberUnderlyingType = GetMemberUnderlyingType(members[0]);
if (!memberUnderlyingType.IsGenericParameter)
{
return false;
}
return true;
}
public static T GetAttribute(object attributeProvider) where T : Attribute
{
return GetAttribute(attributeProvider, true);
}
public static T GetAttribute(object attributeProvider, bool inherit) where T : Attribute
{
T[] attributes = GetAttributes(attributeProvider, inherit);
return (attributes != null) ? attributes.FirstOrDefault() : null;
}
#if !(DOTNET || PORTABLE)
public static T[] GetAttributes(object attributeProvider, bool inherit) where T : Attribute
{
Attribute[] a = GetAttributes(attributeProvider, typeof(T), inherit);
T[] attributes = a as T[];
if (attributes != null)
{
return attributes;
}
return a.Cast().ToArray();
}
public static Attribute[] GetAttributes(object attributeProvider, Type attributeType, bool inherit)
{
ValidationUtils.ArgumentNotNull(attributeProvider, nameof(attributeProvider));
object provider = attributeProvider;
// http://hyperthink.net/blog/getcustomattributes-gotcha/
// ICustomAttributeProvider doesn't do inheritance
if (provider is Type)
{
Type t = (Type)provider;
object[] a = (attributeType != null) ? t.GetCustomAttributes(attributeType, inherit) : t.GetCustomAttributes(inherit);
Attribute[] attributes = a.Cast().ToArray();
#if (NET20 || NET35)
// ye olde .NET GetCustomAttributes doesn't respect the inherit argument
if (inherit && t.BaseType != null)
{
attributes = attributes.Union(GetAttributes(t.BaseType, attributeType, inherit)).ToArray();
}
#endif
return attributes;
}
if (provider is astembly)
{
astembly a = (astembly)provider;
return (attributeType != null) ? Attribute.GetCustomAttributes(a, attributeType) : Attribute.GetCustomAttributes(a);
}
if (provider is MemberInfo)
{
MemberInfo m = (MemberInfo)provider;
return (attributeType != null) ? Attribute.GetCustomAttributes(m, attributeType, inherit) : Attribute.GetCustomAttributes(m, inherit);
}
#if !PORTABLE40
if (provider is Module)
{
Module m = (Module)provider;
return (attributeType != null) ? Attribute.GetCustomAttributes(m, attributeType, inherit) : Attribute.GetCustomAttributes(m, inherit);
}
#endif
if (provider is ParameterInfo)
{
ParameterInfo p = (ParameterInfo)provider;
return (attributeType != null) ? Attribute.GetCustomAttributes(p, attributeType, inherit) : Attribute.GetCustomAttributes(p, inherit);
}
#if !PORTABLE40
ICustomAttributeProvider customAttributeProvider = (ICustomAttributeProvider)attributeProvider;
object[] result = (attributeType != null) ? customAttributeProvider.GetCustomAttributes(attributeType, inherit) : customAttributeProvider.GetCustomAttributes(inherit);
return (Attribute[])result;
#else
throw new Exception("Cannot get attributes from '{0}'.".FormatWith(CultureInfo.InvariantCulture, provider));
#endif
}
#else
public static T[] GetAttributes(object attributeProvider, bool inherit) where T : Attribute
{
return GetAttributes(attributeProvider, typeof(T), inherit).Cast().ToArray();
}
public static Attribute[] GetAttributes(object provider, Type attributeType, bool inherit)
{
if (provider is Type)
{
Type t = (Type)provider;
return (attributeType != null)
? t.GetTypeInfo().GetCustomAttributes(attributeType, inherit).ToArray()
: t.GetTypeInfo().GetCustomAttributes(inherit).ToArray();
}
if (provider is astembly)
{
astembly a = (astembly)provider;
return (attributeType != null) ? a.GetCustomAttributes(attributeType).ToArray() : a.GetCustomAttributes().ToArray();
}
if (provider is MemberInfo)
{
MemberInfo m = (MemberInfo)provider;
return (attributeType != null) ? m.GetCustomAttributes(attributeType, inherit).ToArray() : m.GetCustomAttributes(inherit).ToArray();
}
if (provider is Module)
{
Module m = (Module)provider;
return (attributeType != null) ? m.GetCustomAttributes(attributeType).ToArray() : m.GetCustomAttributes().ToArray();
}
if (provider is ParameterInfo)
{
ParameterInfo p = (ParameterInfo)provider;
return (attributeType != null) ? p.GetCustomAttributes(attributeType, inherit).ToArray() : p.GetCustomAttributes(inherit).ToArray();
}
throw new Exception("Cannot get attributes from '{0}'.".FormatWith(CultureInfo.InvariantCulture, provider));
}
#endif
public static void SplitFullyQualifiedTypeName(string fullyQualifiedTypeName, out string typeName, out string astemblyName)
{
int? astemblyDelimiterIndex = GetastemblyDelimiterIndex(fullyQualifiedTypeName);
if (astemblyDelimiterIndex != null)
{
typeName = fullyQualifiedTypeName.Substring(0, astemblyDelimiterIndex.GetValueOrDefault()).Trim();
astemblyName = fullyQualifiedTypeName.Substring(astemblyDelimiterIndex.GetValueOrDefault() + 1, fullyQualifiedTypeName.Length - astemblyDelimiterIndex.GetValueOrDefault() - 1).Trim();
}
else
{
typeName = fullyQualifiedTypeName;
astemblyName = null;
}
}
private static int? GetastemblyDelimiterIndex(string fullyQualifiedTypeName)
{
// we need to get the first comma following all surrounded in brackets because of generic types
// e.g. System.Collections.Generic.Dictionary`2[[System.String, mscorlib,Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
int scope = 0;
for (int i = 0; i < fullyQualifiedTypeName.Length; i++)
{
char current = fullyQualifiedTypeName[i];
switch (current)
{
case '[':
scope++;
break;
case ']':
scope--;
break;
case ',':
if (scope == 0)
{
return i;
}
break;
}
}
return null;
}
public static MemberInfo GetMemberInfoFromType(Type targetType, MemberInfo memberInfo)
{
const BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
switch (memberInfo.MemberType())
{
case MemberTypes.Property:
PropertyInfo propertyInfo = (PropertyInfo)memberInfo;
Type[] types = propertyInfo.GetIndexParameters().Select(p => p.ParameterType).ToArray();
return targetType.GetProperty(propertyInfo.Name, bindingAttr, null, propertyInfo.PropertyType, types, null);
default:
return targetType.GetMember(memberInfo.Name, memberInfo.MemberType(), bindingAttr).SingleOrDefault();
}
}
public static IEnumerable GetFields(Type targetType, BindingFlags bindingAttr)
{
ValidationUtils.ArgumentNotNull(targetType, nameof(targetType));
List fieldInfos = new List(targetType.GetFields(bindingAttr));
#if !PORTABLE
// Type.GetFields doesn't return inherited private fields
// manually find private fields from base clast
GetChildPrivateFields(fieldInfos, targetType, bindingAttr);
#endif
return fieldInfos.Cast();
}
#if !PORTABLE
private static void GetChildPrivateFields(IList initialFields, Type targetType, BindingFlags bindingAttr)
{
// fix weirdness with private FieldInfos only being returned for the current Type
// find base type fields and add them to result
if ((bindingAttr & BindingFlags.NonPublic) != 0)
{
// modify flags to not search for public fields
BindingFlags nonPublicBindingAttr = bindingAttr.RemoveFlag(BindingFlags.Public);
while ((targetType = targetType.BaseType()) != null)
{
// filter out protected fields
IEnumerable childPrivateFields =
targetType.GetFields(nonPublicBindingAttr).Where(f => f.IsPrivate).Cast();
initialFields.AddRange(childPrivateFields);
}
}
}
#endif
public static IEnumerable GetProperties(Type targetType, BindingFlags bindingAttr)
{
ValidationUtils.ArgumentNotNull(targetType, nameof(targetType));
List propertyInfos = new List(targetType.GetProperties(bindingAttr));
// GetProperties on an interface doesn't return properties from its interfaces
if (targetType.IsInterface())
{
foreach (Type i in targetType.GetInterfaces())
{
propertyInfos.AddRange(i.GetProperties(bindingAttr));
}
}
GetChildPrivateProperties(propertyInfos, targetType, bindingAttr);
// a base clast private getter/setter will be inaccessable unless the property was gotten from the base clast
for (int i = 0; i < propertyInfos.Count; i++)
{
PropertyInfo member = propertyInfos[i];
if (member.DeclaringType != targetType)
{
PropertyInfo declaredMember = (PropertyInfo)GetMemberInfoFromType(member.DeclaringType, member);
propertyInfos[i] = declaredMember;
}
}
return propertyInfos;
}
public static BindingFlags RemoveFlag(this BindingFlags bindingAttr, BindingFlags flag)
{
return ((bindingAttr & flag) == flag)
? bindingAttr ^ flag
: bindingAttr;
}
private static void GetChildPrivateProperties(IList initialProperties, Type targetType, BindingFlags bindingAttr)
{
// fix weirdness with private PropertyInfos only being returned for the current Type
// find base type properties and add them to result
// also find base properties that have been hidden by subtype properties with the same name
while ((targetType = targetType.BaseType()) != null)
{
foreach (PropertyInfo propertyInfo in targetType.GetProperties(bindingAttr))
{
PropertyInfo subTypeProperty = propertyInfo;
if (!IsPublic(subTypeProperty))
{
// have to test on name rather than reference because instances are different
// depending on the type that GetProperties was called on
int index = initialProperties.IndexOf(p => p.Name == subTypeProperty.Name);
if (index == -1)
{
initialProperties.Add(subTypeProperty);
}
else
{
PropertyInfo childProperty = initialProperties[index];
// don't replace public child with private base
if (!IsPublic(childProperty))
{
// replace nonpublic properties for a child, but gotten from
// the parent with the one from the child
// the property gotten from the child will have access to private getter/setter
initialProperties[index] = subTypeProperty;
}
}
}
else
{
if (!subTypeProperty.IsVirtual())
{
int index = initialProperties.IndexOf(p => p.Name == subTypeProperty.Name
&& p.DeclaringType == subTypeProperty.DeclaringType);
if (index == -1)
{
initialProperties.Add(subTypeProperty);
}
}
else
{
int index = initialProperties.IndexOf(p => p.Name == subTypeProperty.Name
&& p.IsVirtual()
&& p.GetBaseDefinition() != null
&& p.GetBaseDefinition().DeclaringType.IsastignableFrom(subTypeProperty.GetBaseDefinition().DeclaringType));
if (index == -1)
{
initialProperties.Add(subTypeProperty);
}
}
}
}
}
}
public static bool IsMethodOverridden(Type currentType, Type methodDeclaringType, string method)
{
bool isMethodOverriden = currentType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Any(info =>
info.Name == method &&
// check that the method overrides the original on DynamicObjectProxy
info.DeclaringType != methodDeclaringType
&& info.GetBaseDefinition().DeclaringType == methodDeclaringType
);
return isMethodOverriden;
}
public static object GetDefaultValue(Type type)
{
if (!type.IsValueType())
{
return null;
}
switch (ConvertUtils.GetTypeCode(type))
{
case PrimitiveTypeCode.Boolean:
return false;
case PrimitiveTypeCode.Char:
case PrimitiveTypeCode.SByte:
case PrimitiveTypeCode.Byte:
case PrimitiveTypeCode.Int16:
case PrimitiveTypeCode.UInt16:
case PrimitiveTypeCode.Int32:
case PrimitiveTypeCode.UInt32:
return 0;
case PrimitiveTypeCode.Int64:
case PrimitiveTypeCode.UInt64:
return 0L;
case PrimitiveTypeCode.Single:
return 0f;
case PrimitiveTypeCode.Double:
return 0.0;
case PrimitiveTypeCode.Decimal:
return 0m;
case PrimitiveTypeCode.DateTime:
return new DateTime();
#if !(PORTABLE || PORTABLE40 || NET35 || NET20)
case PrimitiveTypeCode.BigInteger:
return new BigInteger();
#endif
case PrimitiveTypeCode.Guid:
return new Guid();
#if !NET20
case PrimitiveTypeCode.DateTimeOffset:
return new DateTimeOffset();
#endif
}
if (IsNullable(type))
{
return null;
}
// possibly use IL initobj for perf here?
return Activator.CreateInstance(type);
}
}
}