Mercurial > pub > bltoolkit
view Source/Reflection/TypeHelper.cs @ 3:1ef98bd70424
!bug 100 +3h
Исправление проблемы BLToolkit + mono 3.4
author | cin |
---|---|
date | Fri, 22 Aug 2014 17:34:46 +0400 |
parents | f990fcb411a9 |
children |
line wrap: on
line source
using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Reflection; using System.Xml; #if !SILVERLIGHT using System.Xml.Linq; #endif namespace BLToolkit.Reflection { #if !SILVERLIGHT && !DATA using EditableObjects; #endif using DataAccess; using TypeBuilder; /// <summary> /// A wrapper around the <see cref="Type"/> class. /// </summary> [System.Diagnostics.DebuggerDisplay("Type = {Type}")] public class TypeHelper { /// <summary> /// Initializes a new instance of the <see cref="TypeHelper"/> class. /// </summary> /// <param name="type">The Type to wrap.</param> public TypeHelper(Type type) { if (type == null) throw new ArgumentNullException("type"); Type = type; } /// <summary> /// Gets associated Type. /// </summary> public Type Type { get; private set; } /// <summary> /// Converts the supplied <see cref="Type"/> to a <see cref="TypeHelper"/>. /// </summary> /// <param name="type">The Type.</param> /// <returns>A TypeHelper.</returns> public static implicit operator TypeHelper(Type type) { if (type == null) throw new ArgumentNullException("type"); return new TypeHelper(type); } /// <summary> /// Converts the supplied <see cref="TypeHelper"/> to a <see cref="Type"/>. /// </summary> /// <param name="typeHelper">The TypeHelper.</param> /// <returns>A Type.</returns> public static implicit operator Type(TypeHelper typeHelper) { if (typeHelper == null) throw new ArgumentNullException("typeHelper"); return typeHelper.Type; } #region GetAttributes /// <summary> /// Returns an array of custom attributes identified by <b>Type</b>. /// </summary> /// <param name="attributeType">The type of attribute to search for. /// Only attributes that are assignable to this type are returned.</param> /// <param name="inherit">Specifies whether to search this member's inheritance chain /// to find the attributes.</param> /// <returns>An array of custom attributes defined on this reflected member, /// or an array with zero (0) elements if no attributes are defined.</returns> public object[] GetCustomAttributes(Type attributeType, bool inherit) { return Type.GetCustomAttributes(attributeType, inherit); } /// <summary> /// Returns an array of custom attributes identified by <b>Type</b> /// including attribute's inheritance chain. /// </summary> /// <param name="attributeType">The type of attribute to search for. /// Only attributes that are assignable to this type are returned.</param> /// <returns>An array of custom attributes defined on this reflected member, /// or an array with zero (0) elements if no attributes are defined.</returns> public object[] GetCustomAttributes(Type attributeType) { return Type.GetCustomAttributes(attributeType, true); } /// <summary> /// Returns an array of all of the custom attributes. /// </summary> /// <param name="inherit">Specifies whether to search this member's inheritance chain /// to find the attributes.</param> /// <returns>An array of custom attributes defined on this reflected member, /// or an array with zero (0) elements if no attributes are defined.</returns> public object[] GetCustomAttributes(bool inherit) { return Type.GetCustomAttributes(inherit); } /// <summary> /// Returns an array of all of the custom attributes including attributes' inheritance chain. /// </summary> /// <returns>An array of custom attributes defined on this reflected member, /// or an array with zero (0) elements if no attributes are defined.</returns> public object[] GetCustomAttributes() { return Type.GetCustomAttributes(true); } /// <summary> /// Returns an array of all custom attributes identified by <b>Type</b> including type's /// inheritance chain. /// </summary> /// <param name="attributeType">The type of attribute to search for. /// Only attributes that are assignable to this type are returned.</param> /// <returns>An array of custom attributes defined on this reflected member, /// or an array with zero (0) elements if no attributes are defined.</returns> public object[] GetAttributes(Type attributeType) { return GetAttributes(Type, attributeType); } /// <summary> /// Returns an array of all custom attributes including type's inheritance chain. /// </summary> /// <returns>An array of custom attributes defined on this reflected member, /// or an array with zero (0) elements if no attributes are defined.</returns> public object[] GetAttributes() { return GetAttributesInternal(); } #region Attributes cache object[] GetAttributesInternal() { lock (_typeAttributes) { var key = Type.FullName; object[] attrs; if (!_typeAttributes.TryGetValue(key, out attrs)) { var list = new List<object>(); GetAttributesInternal(list, Type); _typeAttributes.Add(key, attrs = list.ToArray()); } return attrs; } } static readonly Dictionary<Type,object[]> _typeAttributesTopInternal = new Dictionary<Type,object[]>(10); static void GetAttributesInternal(List<object> list, Type type) { object[] attrs; if (_typeAttributesTopInternal.TryGetValue(type, out attrs)) list.AddRange(attrs); else { GetAttributesTreeInternal(list, type); _typeAttributesTopInternal.Add(type, list.ToArray()); } } static readonly Dictionary<Type,object[]> _typeAttributesInternal = new Dictionary<Type,object[]>(10); static void GetAttributesTreeInternal(List<object> list, Type type) { object[] attrs; if (!_typeAttributesInternal.TryGetValue(type, out attrs)) _typeAttributesInternal.Add(type, attrs = type.GetCustomAttributes(false)); if (Common.Configuration.FilterOutBaseEqualAttributes) { foreach (var t in attrs) if (!list.Contains(t)) list.Add(t); } else list.AddRange(attrs); if (type.IsInterface) return; // Reflection returns interfaces for the whole inheritance chain. // So, we are going to get some hemorrhoid here to restore the inheritance sequence. // var interfaces = type.GetInterfaces(); var nBaseInterfaces = type.BaseType != null? type.BaseType.GetInterfaces().Length: 0; for (var i = 0; i < interfaces.Length; i++) { var intf = interfaces[i]; if (i < nBaseInterfaces) { var getAttr = false; foreach (var mi in type.GetInterfaceMap(intf).TargetMethods) { // Check if the interface is reimplemented. // if (mi.DeclaringType == type) { getAttr = true; break; } } if (getAttr == false) continue; } GetAttributesTreeInternal(list, intf); } if (type.BaseType != null && type.BaseType != typeof(object)) GetAttributesTreeInternal(list, type.BaseType); } static readonly Dictionary<string,object[]> _typeAttributes = new Dictionary<string, object[]>(10); #endregion /// <summary> /// Returns an array of custom attributes applied to a type. /// </summary> /// <param name="type">A type instance.</param> /// <param name="attributeType">The type of attribute to search for. /// Only attributes that are assignable to this type are returned.</param> /// <returns>An array of custom attributes applied to this type, /// or an array with zero (0) elements if no attributes have been applied.</returns> public static object[] GetAttributes(Type type, Type attributeType) { if (type == null) throw new ArgumentNullException("type"); if (attributeType == null) throw new ArgumentNullException("attributeType"); lock (_typeAttributes) { var key = type.FullName + "#" + attributeType.FullName; object[] attrs; if (!_typeAttributes.TryGetValue(key, out attrs)) { var list = new List<object>(); GetAttributesInternal(list, type); for (var i = 0; i < list.Count; i++) if (attributeType.IsInstanceOfType(list[i]) == false) list.RemoveAt(i--); _typeAttributes.Add(key, attrs = list.ToArray()); } return attrs; } } /// <summary> /// Retrieves a custom attribute applied to a type. /// </summary> /// <param name="type">A type instance.</param> /// <param name="attributeType">The type of attribute to search for. /// Only attributes that are assignable to this type are returned.</param> /// <returns>A reference to the first custom attribute of type <paramref name="attributeType"/> /// that is applied to element, or null if there is no such attribute.</returns> public static Attribute GetFirstAttribute(Type type, Type attributeType) { var attrs = new TypeHelper(type).GetAttributes(attributeType); return attrs.Length > 0? (Attribute)attrs[0]: null; } /// <summary> /// Retrieves a custom attribute applied to a type. /// </summary> /// <param name="type">A type instance.</param> /// <typeparam name="T">The type of attribute to search for. /// Only attributes that are assignable to this type are returned.</param> /// <returns>A reference to the first custom attribute of type attributeType /// that is applied to element, or null if there is no such attribute.</returns> public static T GetFirstAttribute<T>(Type type) where T : Attribute { var attrs = new TypeHelper(type).GetAttributes(typeof(T)); return attrs.Length > 0? (T)attrs[0]: null; } #endregion #region Property Wrappers /// <summary> /// Gets the fully qualified name of the Type, including the namespace of the Type. /// </summary> public string FullName { get { return Type.FullName; } } /// <summary> /// Gets the name of the Type. /// </summary> public string Name { get { return Type.Name; } } /// <summary> /// Gets a value indicating whether the Type is abstract and must be overridden. /// </summary> public bool IsAbstract { get { return Type.IsAbstract; } } /// <summary> /// Gets a value indicating whether the System.Type is an array. /// </summary> public bool IsArray { get { return Type.IsArray; } } /// <summary> /// Gets a value indicating whether the Type is a value type. /// </summary> public bool IsValueType { get { return Type.IsValueType; } } /// <summary> /// Gets a value indicating whether the Type is a class; that is, not a value type or interface. /// </summary> public bool IsClass { get { return Type.IsClass; } } /// <summary> /// Gets a value indicating whether the System.Type is an interface; that is, not a class or a value type. /// </summary> public bool IsInterface { get { return Type.IsInterface; } } /// <summary> /// Indicates whether the Type is serializable. /// </summary> public bool IsSerializable { get { #if SILVERLIGHT return false; #else return Type.IsSerializable; #endif } } #endregion #region GetMethods /// <summary> /// Returns all the methods of the current Type. /// </summary> /// <returns>An array of <see cref="MethodInfo"/> objects representing all methods /// defined for the current Type.</returns> public MethodInfo[] GetMethods() { return Type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } /// <summary> /// Returns all the public methods of the current Type. /// </summary> /// <returns>An array of <see cref="MethodInfo"/> objects representing all the public methods /// defined for the current Type.</returns> public MethodInfo[] GetPublicMethods() { return Type.GetMethods(BindingFlags.Instance | BindingFlags.Public); } /// <summary> /// Searches for the methods defined for the current Type, /// using the specified binding constraints. /// </summary> /// <param name="flags">A bitmask comprised of one or more <see cref="BindingFlags"/> /// that specify how the search is conducted.</param> /// <returns>An array of <see cref="MethodInfo"/> objects representing all methods defined /// for the current Type that match the specified binding constraints.</returns> public MethodInfo[] GetMethods(BindingFlags flags) { return Type.GetMethods(flags); } /// <summary> /// Returns all the generic or non-generic methods of the current Type. /// </summary> /// <param name="generic">True to return all generic methods, false to return all non-generic.</param> /// <returns>An array of <see cref="MethodInfo"/> objects representing all methods /// defined for the current Type.</returns> public MethodInfo[] GetMethods(bool generic) { return GetMethods(Type, generic, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } /// <summary> /// Returns all the public and non-generic methods of the current Type. /// </summary> /// <param name="generic">True to return all generic methods, false to return all non-generic.</param> /// <returns>An array of <see cref="MethodInfo"/> objects representing all the public methods /// defined for the current Type.</returns> public MethodInfo[] GetPublicMethods(bool generic) { return GetMethods(Type, generic, BindingFlags.Instance | BindingFlags.Public); } /// <summary> /// Searches for the generic methods defined for the current Type, /// using the specified binding constraints. /// </summary> /// <param name="generic">True to return all generic methods, false to return all non-generic.</param> /// <param name="flags">A bitmask comprised of one or more <see cref="BindingFlags"/> /// that specify how the search is conducted.</param> /// <returns>An array of <see cref="MethodInfo"/> objects representing all methods defined /// for the current Type that match the specified binding constraints.</returns> public MethodInfo[] GetMethods(bool generic, BindingFlags flags) { return GetMethods(Type, generic, flags); } #endregion #region GetMethod /// <summary> /// Searches for the specified instance method (public or non-public), using the specified name. /// </summary> /// <param name="methodName">The String containing the name of the method to get.</param> /// <returns>A <see cref="MethodInfo"/> object representing the method /// that matches the specified name, if found; otherwise, null.</returns> public MethodInfo GetMethod(string methodName) { return Type.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } /// <summary> /// Searches for the specified public instance method, using the specified name. /// </summary> /// <param name="methodName">The String containing the name of the method to get.</param> /// <returns>A <see cref="MethodInfo"/> object representing the method /// that matches the specified name, if found; otherwise, null.</returns> public MethodInfo GetPublicMethod(string methodName) { return Type.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public); } /// <summary> /// Searches for the specified method, using the specified name and binding flags. /// </summary> /// <param name="methodName">The String containing the name of the method to get.</param> /// <param name="flags">A bitmask comprised of one or more <see cref="BindingFlags"/> /// that specify how the search is conducted.</param> /// <returns>A <see cref="MethodInfo"/> object representing the method /// that matches the specified requirements, if found; otherwise, null.</returns> public MethodInfo GetMethod(string methodName, BindingFlags flags) { return Type.GetMethod(methodName, flags); } /// <summary> /// Searches for the specified public instance method, using the specified name. /// </summary> /// <param name="methodName">The String containing the name of the method to get.</param> /// <param name="types">An array of <see cref="System.Type"/> objects representing /// the number, order, and type of the parameters for the method to get.-or- /// An empty array of the type <see cref="System.Type"/> (for example, <see cref="System.Type.EmptyTypes"/>) /// to get a method that takes no parameters.</param> /// <returns>A <see cref="MethodInfo"/> object representing the method /// that matches the specified requirements, if found; otherwise, null.</returns> public MethodInfo GetPublicMethod(string methodName, params Type[] types) { return Type.GetMethod( methodName, BindingFlags.Instance | BindingFlags.Public, null, types, null); } /// <summary> /// Searches for the specified instance method (public or non-public), /// using the specified name and argument types. /// </summary> /// <param name="methodName">The String containing the name of the method to get.</param> /// <param name="types">An array of <see cref="System.Type"/> objects representing /// the number, order, and type of the parameters for the method to get.-or- /// An empty array of the type <see cref="System.Type"/> (for example, <see cref="System.Type.EmptyTypes"/>) /// to get a method that takes no parameters.</param> /// <returns>A <see cref="MethodInfo"/> object representing the method /// that matches the specified requirements, if found; otherwise, null.</returns> public MethodInfo GetMethod(string methodName, params Type[] types) { return Type.GetMethod( methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, types, null); } /// <summary> /// Searches for the specified method, using the specified name, /// binding flags and argument types. /// </summary> /// <param name="methodName">The String containing the name of the method to get.</param> /// <param name="types">An array of <see cref="System.Type"/> objects representing /// the number, order, and type of the parameters for the method to get.-or- /// An empty array of the type <see cref="System.Type"/> (for example, <see cref="System.Type.EmptyTypes"/>) /// to get a method that takes no parameters.</param> /// <param name="flags">A bitmask comprised of one or more <see cref="BindingFlags"/> /// that specify how the search is conducted.</param> /// <returns>A <see cref="MethodInfo"/> object representing the method /// that matches the specified requirements, if found; otherwise, null.</returns> public MethodInfo GetMethod(string methodName, BindingFlags flags, params Type[] types) { return Type.GetMethod(methodName, flags, null, types, null); } /// <summary> /// Searches for the specified instance method (public or non-public), using the specified name. /// </summary> /// <param name="methodName">The String containing the name of the method to get.</param> /// <param name="generic">True to search only for a generic method, or /// False to search only for non-generic method.</param> /// <returns>A <see cref="MethodInfo"/> object representing the method /// that matches the specified requirements, if found; otherwise, null.</returns> public MethodInfo GetMethod(bool generic, string methodName) { return GetMethod(Type, generic, methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } /// <summary> /// Searches for the specified public instance method, using the specified name. /// </summary> /// <param name="methodName">The String containing the name of the method to get.</param> /// <param name="generic">True to search only for a generic method, or /// False to search only for non-generic method.</param> /// <returns>A <see cref="MethodInfo"/> object representing the method /// that matches the specified requirements, if found; otherwise, null.</returns> public MethodInfo GetPublicMethod(bool generic, string methodName) { return GetMethod(Type, generic, methodName, BindingFlags.Instance | BindingFlags.Public); } /// <summary> /// Searches for the specified method, using the specified name and binding flags. /// </summary> /// <param name="methodName">The String containing the name of the method to get.</param> /// <param name="generic">True to search only for a generic method, or /// False to search only for non-generic method.</param> /// <param name="flags">A bitmask comprised of one or more <see cref="BindingFlags"/> /// that specify how the search is conducted.</param> /// <returns>A <see cref="MethodInfo"/> object representing the method /// that matches the specified requirements, if found; otherwise, null.</returns> public MethodInfo GetMethod(bool generic, string methodName, BindingFlags flags) { return GetMethod(Type, generic, methodName, flags); } /// <summary> /// Searches for the specified public instance method, using the specified name and argument types. /// </summary> /// <param name="methodName">The String containing the name of the method to get.</param> /// <param name="generic">True to search only for a generic method, or /// False to search only for non-generic method.</param> /// <param name="types">An array of <see cref="System.Type"/> objects representing /// the number, order, and type of the parameters for the method to get.-or- /// An empty array of the type <see cref="System.Type"/> (for example, <see cref="System.Type.EmptyTypes"/>) /// to get a method that takes no parameters.</param> /// <returns>A <see cref="MethodInfo"/> object representing the method /// that matches the specified requirements, if found; otherwise, null.</returns> public MethodInfo GetPublicMethod(bool generic, string methodName, params Type[] types) { return Type.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public, generic ? GenericBinder.Generic : GenericBinder.NonGeneric, types, null); } /// <summary> /// Searches for the specified instance method (public or non-public), /// using the specified name and argument types. /// </summary> /// <param name="methodName">The String containing the name of the method to get.</param> /// <param name="generic">True to search only for a generic method, or /// False to search only for non-generic method.</param> /// <param name="types">An array of <see cref="System.Type"/> objects representing /// the number, order, and type of the parameters for the method to get.-or- /// An empty array of the type <see cref="System.Type"/> (for example, <see cref="System.Type.EmptyTypes"/>) /// to get a method that takes no parameters.</param> /// <returns>A <see cref="MethodInfo"/> object representing the method /// that matches the specified requirements, if found; otherwise, null.</returns> public MethodInfo GetMethod(bool generic, string methodName, params Type[] types) { return Type.GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, generic ? GenericBinder.Generic : GenericBinder.NonGeneric, types, null); } /// <summary> /// Searches for the specified method using the specified name, binding flags and argument types. /// </summary> /// <param name="methodName">The String containing the name of the method to get.</param> /// <param name="generic">True to search only for a generic method, or /// False to search only for non-generic method.</param> /// <param name="types">An array of <see cref="System.Type"/> objects representing /// the number, order, and type of the parameters for the method to get.-or- /// An empty array of the type <see cref="System.Type"/> (for example, <see cref="System.Type.EmptyTypes"/>) /// to get a method that takes no parameters.</param> /// <param name="flags">A bitmask comprised of one or more <see cref="BindingFlags"/> /// that specify how the search is conducted.</param> /// <returns>A <see cref="MethodInfo"/> object representing the method /// that matches the specified requirements, if found; otherwise, null.</returns> public MethodInfo GetMethod(bool generic, string methodName, BindingFlags flags, params Type[] types) { return Type.GetMethod(methodName, flags, generic ? GenericBinder.Generic : GenericBinder.NonGeneric, types, null); } #endregion #region GetFields /// <summary> /// Returns all the public fields of the current Type. /// </summary> /// <returns>An array of <see cref="FieldInfo"/> objects representing /// all the public fields defined for the current Type.</returns> public FieldInfo[] GetFields() { return Type.GetFields(); } /// <summary> /// Searches for the fields of the current Type, using the specified binding constraints. /// </summary> /// <param name="bindingFlags">A bitmask comprised of one or more <see cref="BindingFlags"/> /// that specify how the search is conducted.</param> /// <returns>An array of <see cref="FieldInfo"/> objects representing /// all fields of the current Type /// that match the specified binding constraints.</returns> public FieldInfo[] GetFields(BindingFlags bindingFlags) { return Type.GetFields(bindingFlags); } /// <summary> /// Searches for the public field with the specified name. /// </summary> /// <param name="name">The String containing the name of the public field to get.</param> /// <returns>A <see cref="PropertyInfo"/> object representing the public field with the specified name, /// if found; otherwise, a null reference.</returns> public FieldInfo GetField(string name) { return Type.GetField( name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } #endregion #region GetProperties /// <summary> /// Returns all the public properties of the current Type. /// </summary> /// <returns>An array of <see cref="PropertyInfo"/> objects representing /// all public properties of the current Type.</returns> public PropertyInfo[] GetProperties() { return Type.GetProperties(); } /// <summary> /// Searches for the properties of the current Type, using the specified binding constraints. /// </summary> /// <param name="bindingFlags">A bitmask comprised of one or more <see cref="BindingFlags"/> /// that specify how the search is conducted.</param> /// <returns>An array of <see cref="PropertyInfo"/> objects representing /// all properties of the current Type /// that match the specified binding constraints.</returns> public PropertyInfo[] GetProperties(BindingFlags bindingFlags) { return Type.GetProperties(bindingFlags); } /// <summary> /// Searches for the public property with the specified name. /// </summary> /// <param name="name">The String containing the name of the public property to get.</param> /// <returns>A <see cref="PropertyInfo"/> object representing the public property with the specified name, /// if found; otherwise, a null reference.</returns> public PropertyInfo GetProperty(string name) { return Type.GetProperty( name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } #endregion #region GetInterfaces /* private Type[] _interfaces; /// <summary> /// Gets all the interfaces implemented or inherited by the current <see cref="Type"/>. /// </summary> /// <returns>An array of Type objects representing all the interfaces implemented or /// inherited by the current Type, /// if found; otherwise, an empty array.</returns> public Type[] GetInterfaces() { if (_interfaces == null) _interfaces = _type.GetInterfaces(); return _interfaces; } /// <summary> /// Gets a specific interface implemented or inherited by the current <see cref="Type"/>. /// </summary> /// <param name="interfaceType">The type of the interface to get.</param> /// <returns>A Type object representing the interface of the specified type, if found; /// otherwise, a null reference (Nothing in Visual Basic).</returns> public Type GetInterface(Type interfaceType) { foreach (Type intf in GetInterfaces()) if (intf == interfaceType) return null; _type.IsSubclassOf(interfaceType); return null; } */ /// <summary> /// Returns an interface mapping for the current <see cref="Type"/>. /// </summary> /// <param name="interfaceType">The <see cref="System.Type"/> /// of the interface of which to retrieve a mapping.</param> /// <returns>An <see cref="InterfaceMapping"/> object representing the interface /// mapping for <paramref name="interfaceType"/>.</returns> public InterfaceMapping GetInterfaceMap(Type interfaceType) { return Type.GetInterfaceMap(interfaceType); } #endregion #region GetConstructor /// <summary> /// Searches for a public instance constructor whose parameters match /// the types in the specified array. /// </summary> /// <param name="types">An array of Type objects representing the number, /// order, and type of the parameters for the constructor to get.</param> /// <returns>A <see cref="ConstructorInfo"/> object representing the /// public instance constructor whose parameters match the types in /// the parameter type array, if found; otherwise, a null reference.</returns> public ConstructorInfo GetPublicConstructor(params Type[] types) { return Type.GetConstructor(types); } /// <summary> /// Searches for an instance constructor (public or non-public) whose /// parameters match the types in the specified array. /// </summary> /// <param name="parameterType">Type object representing type of the /// parameter for the constructor to get.</param> /// <returns>A <see cref="ConstructorInfo"/> object representing the constructor /// whose parameters match the types in the parameter type array, if found; /// otherwise, a null reference.</returns> public ConstructorInfo GetConstructor(Type parameterType) { return GetConstructor(Type, parameterType); } /// <summary> /// Searches for an instance constructor (public or non-public) whose /// parameters match the types in the specified array. /// </summary> /// <param name="type">An instance of <see cref="System.Type"/> to search constructor for.</param> /// <param name="types">An array of Type objects representing the number, /// order, and type of the parameters for the constructor to get.</param> /// <returns>A <see cref="ConstructorInfo"/> object representing the constructor /// whose parameters match the types in the parameter type array, if found; /// otherwise, a null reference.</returns> public static ConstructorInfo GetConstructor(Type type, params Type[] types) { if (type == null) throw new ArgumentNullException("type"); return type.GetConstructor( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, types, null); } /// <summary> /// Searches for a public default constructor. /// </summary> /// <returns>A <see cref="ConstructorInfo"/> object representing the constructor.</returns> public ConstructorInfo GetPublicDefaultConstructor() { return Type.GetConstructor(Type.EmptyTypes); } /// <summary> /// Searches for a default constructor. /// </summary> /// <returns>A <see cref="ConstructorInfo"/> object representing the constructor.</returns> public ConstructorInfo GetDefaultConstructor() { return GetDefaultConstructor(Type); } /// <summary> /// Searches for a default constructor. /// </summary> /// <param name="type">An instance of <see cref="System.Type"/> to search constructor for.</param> /// <returns>A <see cref="ConstructorInfo"/> object representing the constructor.</returns> public static ConstructorInfo GetDefaultConstructor(Type type) { if (type == null) throw new ArgumentNullException("type"); return type.GetConstructor( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); } /// <summary> /// Searches for a public constructors. /// </summary> /// <returns>An array of <see cref="ConstructorInfo"/> objects /// representing all the type public constructors, if found; otherwise, an empty array.</returns> public ConstructorInfo[] GetPublicConstructors() { return Type.GetConstructors(); } /// <summary> /// Searches for all constructors (except type constructors). /// </summary> /// <returns>An array of <see cref="ConstructorInfo"/> objects /// representing all the type constructors, if found; otherwise, an empty array.</returns> public ConstructorInfo[] GetConstructors() { return Type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } #endregion #region Static Members /// <summary> /// Gets a value indicating whether a type (or type's element type) /// instance can be null in the underlying data store. /// </summary> /// <param name="type">A <see cref="System.Type"/> instance. </param> /// <returns> True, if the type parameter is a closed generic nullable type; otherwise, False.</returns> /// <remarks>Arrays of Nullable types are treated as Nullable types.</remarks> public static bool IsNullable(Type type) { while (type.IsArray) type = type.GetElementType(); return (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)); } public static bool IsNullableType(Type type) { return (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)); } public static bool IsNullableEnum(Type type) { return IsNullableType(type) && type.GetGenericArguments()[0].IsEnum; } public static bool IsEnumOrNullableEnum(Type type) { return type.IsEnum || IsNullableEnum(type); } public static Type ToNullable(Type type) { if (!IsNullable(type) && type.IsValueType) { var nullable = typeof(Nullable<>); var typeArguments = nullable.GetGenericArguments(); if (typeArguments != null && typeArguments.Length == 1) { type = nullable.MakeGenericType(type); } } return type; } /// <summary> /// Returns the underlying type argument of the specified type. /// </summary> /// <param name="type">A <see cref="System.Type"/> instance. </param> /// <returns><list> /// <item>The type argument of the type parameter, /// if the type parameter is a closed generic nullable type.</item> /// <item>The underlying Type if the type parameter is an enum type.</item> /// <item>Otherwise, the type itself.</item> /// </list> /// </returns> public static Type GetUnderlyingType(Type type) { if (type == null) throw new ArgumentNullException("type"); if (IsNullableType(type)) type = type.GetGenericArguments()[0]; if (type.IsEnum) type = Enum.GetUnderlyingType(type); return type; } public static Type UnwrapNullableType(Type type) { if (type == null) throw new ArgumentNullException("type"); return IsNullableType(type) ? type.GetGenericArguments()[0] : type; } public static IEnumerable<Type> GetDefiningTypes(Type child, MemberInfo member) { if (member.MemberType == MemberTypes.Property) { var prop = (PropertyInfo)member; member = prop.GetGetMethod(); } foreach (var inf in child.GetInterfaces()) { var pm = child.GetInterfaceMap(inf); for (var i = 0; i < pm.TargetMethods.Length; i++) { var method = pm.TargetMethods[i]; if (method == member || (method.DeclaringType == member.DeclaringType && method.Name == member.Name)) yield return inf; } } yield return member.DeclaringType; } public static bool IsAbstractClass(Type type) { return type.IsClass && type.IsAbstract; } /// <summary> /// Determines whether the specified types are considered equal. /// </summary> /// <param name="parent">A <see cref="System.Type"/> instance. </param> /// <param name="child">A type possible derived from the <c>parent</c> type</param> /// <returns>True, when an object instance of the type <c>child</c> /// can be used as an object of the type <c>parent</c>; otherwise, false.</returns> /// <remarks>Note that nullable types does not have a parent-child relation to it's underlying type. /// For example, the 'int?' type (nullable int) and the 'int' type /// aren't a parent and it's child.</remarks> public static bool IsSameOrParent([JetBrains.Annotations.NotNull] Type parent, [JetBrains.Annotations.NotNull] Type child) { if (parent == null) throw new ArgumentNullException("parent"); if (child == null) throw new ArgumentNullException("child"); if (parent == child || child.IsEnum && Enum.GetUnderlyingType(child) == parent || child.IsSubclassOf(parent)) { return true; } if (parent.IsGenericTypeDefinition) for (var t = child; t != typeof(object) && t != null; t = t.BaseType) if (t.IsGenericType && t.GetGenericTypeDefinition() == parent) return true; if (parent.IsInterface) { var interfaces = child.GetInterfaces(); foreach (var t in interfaces) { if (parent.IsGenericTypeDefinition) { if (t.IsGenericType && t.GetGenericTypeDefinition() == parent) return true; } else if (t == parent) return true; } } return false; } public static Type GetGenericType([JetBrains.Annotations.NotNull] Type genericType, Type type) { if (genericType == null) throw new ArgumentNullException("genericType"); while (type != null && type != typeof(object)) { if (type.IsGenericType && type.GetGenericTypeDefinition() == genericType) return type; if (genericType.IsInterface) { foreach (var interfaceType in type.GetInterfaces()) { var gType = GetGenericType(genericType, interfaceType); if (gType != null) return gType; } } type = type.BaseType; } return null; } /// <summary> /// Searches for the method defined for a <see cref="System.Type"/>, /// using the specified name and binding flags. /// </summary> /// <param name="methodName">The String containing the name of the method to get.</param> /// <param name="generic">True to search only for a generic method, or /// False to search only for non-generic method.</param> /// <param name="type">A <see cref="System.Type"/> instance. </param> /// <param name="flags">A bitmask comprised of one or more <see cref="BindingFlags"/> /// that specify how the search is conducted.</param> /// <returns>A <see cref="MethodInfo"/> object representing the method /// that matches the specified requirements, if found; otherwise, null.</returns> public static MethodInfo GetMethod([JetBrains.Annotations.NotNull] Type type, bool generic, string methodName, BindingFlags flags) { if (type == null) throw new ArgumentNullException("type"); foreach (var method in type.GetMethods(flags)) if (method.IsGenericMethodDefinition == generic && method.Name == methodName) return method; return null; } /// <summary> /// Searches for the methods defined for a <see cref="System.Type"/>, /// using the specified name and binding flags. /// </summary> /// <param name="type">A <see cref="System.Type"/> instance. </param> /// <param name="generic">True to return all generic methods, false to return all non-generic.</param> /// <param name="flags">A bitmask comprised of one or more <see cref="BindingFlags"/> /// that specify how the search is conducted.</param> /// <returns>An array of <see cref="MethodInfo"/> objects representing all methods defined /// for the current Type that match the specified binding constraints.</returns> public static MethodInfo[] GetMethods(Type type, bool generic, BindingFlags flags) { if (type == null) throw new ArgumentNullException("type"); return type.GetMethods(flags).Where(method => method.IsGenericMethodDefinition == generic).ToArray(); } /// <summary> /// Searches for the method defined for a <see cref="System.Type"/>, /// using the specified name and binding flags. /// </summary> /// <param name="type">A <see cref="System.Type"/> instance. </param> /// <param name="methodName">The String containing the name of the method to get.</param> /// <param name="requiredParametersCount">Number of required (non optional) /// parameter types.</param> /// <param name="bindingFlags">A bitmask comprised of one or more <see cref="BindingFlags"/> /// that specify how the search is conducted.</param> /// <param name="parameterTypes">An array of <see cref="System.Type"/> objects representing /// the number, order, and type of the parameters for the method to get.-or- /// An empty array of the type <see cref="System.Type"/> (for example, <see cref="System.Type.EmptyTypes"/>) /// to get a method that takes no parameters.</param> /// <returns>A <see cref="MethodInfo"/> object representing the method /// that matches the specified requirements, if found; otherwise, null.</returns> public static MethodInfo GetMethod( Type type, string methodName, BindingFlags bindingFlags, int requiredParametersCount, params Type[] parameterTypes) { while (parameterTypes.Length >= requiredParametersCount) { var method = type.GetMethod(methodName, parameterTypes); if (null != method) return method; if (parameterTypes.Length == 0) break; Array.Resize(ref parameterTypes, parameterTypes.Length - 1); } return null; } [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] public static object[] GetPropertyParameters(PropertyInfo propertyInfo) { if (propertyInfo == null) throw new ArgumentNullException("propertyInfo"); var attrs = propertyInfo.GetCustomAttributes(typeof(ParameterAttribute), true); if (attrs != null && attrs.Length > 0) return ((ParameterAttribute)attrs[0]).Parameters; attrs = propertyInfo.GetCustomAttributes(typeof(InstanceTypeAttribute), true); if (attrs.Length > 0) return ((InstanceTypeAttribute)attrs[0]).Parameters; attrs = new TypeHelper( propertyInfo.DeclaringType).GetAttributes(typeof(GlobalInstanceTypeAttribute)); foreach (GlobalInstanceTypeAttribute attr in attrs) if (IsSameOrParent(attr.PropertyType, propertyInfo.PropertyType)) // if (attr.PropertyType == propertyInfo.PropertyType) return attr.Parameters; return null; } /// <summary> /// Searches for the property defined for a <see cref="System.Type"/>, /// using the specified name and parameter types. /// </summary> /// <param name="type">A <see cref="System.Type"/> instance. </param> /// <param name="propertyName">The String containing the name of the method to get.</param> /// <param name="types">An array of Type objects representing the number, /// order, and type of the parameters for the constructor to get.</param> /// <param name="returnType">The property return <see cref="System.Type"/>. </param> /// <returns>A <see cref="MethodInfo"/> object representing the method /// that matches the specified requirements, if found; otherwise, null.</returns> public static PropertyInfo GetPropertyInfo( Type type, string propertyName, Type returnType, Type[] types) { if (type == null) throw new ArgumentNullException("type"); return type.GetProperty( propertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, returnType, types, null); } ///<summary> /// Gets the Type of a list item. ///</summary> /// <param name="list">A <see cref="System.Object"/> instance. </param> ///<returns>The Type instance that represents the exact runtime type of a list item.</returns> public static Type GetListItemType(object list) { var typeOfObject = typeof(object); if (list == null) return typeOfObject; #if !SILVERLIGHT && !DATA if (list is EditableArrayList) return ((EditableArrayList)list).ItemType; #endif if (list is Array) return list.GetType().GetElementType(); var type = list.GetType(); // object[] attrs = type.GetCustomAttributes(typeof(DefaultMemberAttribute), true); // string itemMemberName = (attrs.Length == 0)? "Item": ((DefaultMemberAttribute)attrs[0]).MemberName; if (list is IList #if !SILVERLIGHT || list is ITypedList || list is IListSource #endif ) { PropertyInfo last = null; foreach (var pi in type.GetProperties()) { if (pi.GetIndexParameters().Length > 0 && pi.PropertyType != typeOfObject) { if (pi.Name == "Item") return pi.PropertyType; last = pi; } } if (last != null) return last.PropertyType; } try { if (list is IList) { foreach (var o in (IList)list) if (o != null && o.GetType() != typeOfObject) return o.GetType(); } else if (list is IEnumerable) { foreach (var o in (IEnumerable)list) if (o != null && o.GetType() != typeOfObject) return o.GetType(); } } catch { } return typeOfObject; } ///<summary> /// Gets the Type of a list item. ///</summary> /// <param name="listType">A <see cref="System.Type"/> instance. </param> ///<returns>The Type instance that represents the exact runtime type of a list item.</returns> public static Type GetListItemType(Type listType) { if (listType.IsGenericType) { var elementTypes = GetGenericArguments(listType, typeof(IList)); if (elementTypes != null) return elementTypes[0]; } if (IsSameOrParent(typeof(IList), listType) #if !SILVERLIGHT || IsSameOrParent(typeof(ITypedList), listType) || IsSameOrParent(typeof(IListSource), listType) #endif ) { var elementType = listType.GetElementType(); if (elementType != null) return elementType; PropertyInfo last = null; foreach (var pi in listType.GetProperties()) { if (pi.GetIndexParameters().Length > 0 && pi.PropertyType != typeof(object)) { if (pi.Name == "Item") return pi.PropertyType; last = pi; } } if (last != null) return last.PropertyType; } return typeof(object); } public static Type GetElementType(Type type) { if (type == null) return null; if (type == typeof(object)) return type.HasElementType ? type.GetElementType(): null; if (type.IsArray) return type.GetElementType(); if (type.IsGenericType) foreach (var aType in type.GetGenericArguments()) if (typeof(IEnumerable<>).MakeGenericType(new[] { aType }).IsAssignableFrom(type)) return aType; var interfaces = type.GetInterfaces(); if (interfaces != null && interfaces.Length > 0) { foreach (var iType in interfaces) { var eType = GetElementType(iType); if (eType != null) return eType; } } return GetElementType(type.BaseType); } /// <summary> /// Gets a value indicating whether a type can be used as a db primitive. /// </summary> /// <param name="type">A <see cref="System.Type"/> instance. </param> /// <returns> True, if the type parameter is a primitive type; otherwise, False.</returns> /// <remarks><see cref="System.String"/>. <see cref="Stream"/>. /// <see cref="XmlReader"/>. <see cref="XmlDocument"/>. are specially handled by the library /// and, therefore, can be treated as scalar types.</remarks> public static bool IsScalar(Type type) { while (type.IsArray) type = type.GetElementType(); return type.IsValueType || type == typeof(string) || type == typeof(System.Data.Linq.Binary) || type == typeof(Stream) || type == typeof(XmlReader) || type.GetCustomAttributes(typeof(ScalarAttribute),true).Any() // If the type is a UDT pass it as is #if !SILVERLIGHT || type == typeof(XmlDocument) || type == typeof(XElement) #endif ; } ///<summary> /// Returns an array of Type objects that represent the type arguments /// of a generic type or the type parameters of a generic type definition. ///</summary> /// <param name="type">A <see cref="System.Type"/> instance.</param> ///<param name="baseType">Non generic base type.</param> ///<returns>An array of Type objects that represent the type arguments /// of a generic type. Returns an empty array if the current type is not a generic type.</returns> public static Type[] GetGenericArguments(Type type, Type baseType) { var baseTypeName = baseType.Name; for (var t = type; t != typeof(object) && t != null; t = t.BaseType) { if (t.IsGenericType) { if (baseType.IsGenericTypeDefinition) { if (t.GetGenericTypeDefinition() == baseType) return t.GetGenericArguments(); } else if (baseTypeName == null || t.Name.Split('`')[0] == baseTypeName) { return t.GetGenericArguments(); } } } foreach (var t in type.GetInterfaces()) { if (t.IsGenericType) { if (baseType.IsGenericTypeDefinition) { if (t.GetGenericTypeDefinition() == baseType) return t.GetGenericArguments(); } else if (baseTypeName == null || t.Name.Split('`')[0] == baseTypeName) { return t.GetGenericArguments(); } } } return null; } /// <summary> /// Substitutes the elements of an array of types for the type parameters /// of the current generic type definition and returns a Type object /// representing the resulting constructed type. /// </summary> /// <param name="type">A <see cref="System.Type"/> instance.</param> /// <param name="typeArguments">An array of types to be substituted for /// the type parameters of the current generic type.</param> /// <returns>A Type representing the constructed type formed by substituting /// the elements of <paramref name="typeArguments"/> for the type parameters /// of the current generic type.</returns> /// <seealso cref="System.Type.MakeGenericType"/> public static Type TranslateGenericParameters(Type type, Type[] typeArguments) { // 'T paramName' case // if (type.IsGenericParameter) return typeArguments[type.GenericParameterPosition]; // 'List<T> paramName' or something like that. // if (type.IsGenericType && type.ContainsGenericParameters) { var genArgs = type.GetGenericArguments(); for (var i = 0; i < genArgs.Length; ++i) genArgs[i] = TranslateGenericParameters(genArgs[i], typeArguments); return type.GetGenericTypeDefinition().MakeGenericType(genArgs); } // Non-generic type. // return type; } public static bool CompareParameterTypes(Type goal, Type probe) { if (goal == probe) return true; if (goal.IsGenericParameter) return CheckConstraints(goal, probe); if (goal.IsGenericType && probe.IsGenericType) return CompareGenericTypes(goal, probe); return false; } public static bool CheckConstraints(Type goal, Type probe) { var constraints = goal.GetGenericParameterConstraints(); for (var i = 0; i < constraints.Length; i++) if (!constraints[i].IsAssignableFrom(probe)) return false; return true; } public static bool CompareGenericTypes(Type goal, Type probe) { var genArgs = goal.GetGenericArguments(); var specArgs = probe.GetGenericArguments(); var match = (genArgs.Length == specArgs.Length); for (var i = 0; match && i < genArgs.Length; i++) { if (genArgs[i] == specArgs[i]) continue; if (genArgs[i].IsGenericParameter) match = CheckConstraints(genArgs[i], specArgs[i]); else if (genArgs[i].IsGenericType && specArgs[i].IsGenericType) match = CompareGenericTypes(genArgs[i], specArgs[i]); else match = false; } return match; } public static PropertyInfo GetPropertyByMethod(MethodInfo method) { if (method != null) { var type = method.DeclaringType; var attr = BindingFlags.NonPublic | BindingFlags.Public | (method.IsStatic ? BindingFlags.Static : BindingFlags.Instance); foreach (var info in type.GetProperties(attr)) { if (info.CanRead && method == info.GetGetMethod(true)) return info; if (info.CanWrite && method == info.GetSetMethod(true)) return info; } } return null; } public static Type GetMemberType(MemberInfo memberInfo) { switch (memberInfo.MemberType) { case MemberTypes.Property : return ((PropertyInfo) memberInfo).PropertyType; case MemberTypes.Field : return ((FieldInfo) memberInfo).FieldType; case MemberTypes.Method : return ((MethodInfo) memberInfo).ReturnType; case MemberTypes.Constructor : return ((ConstructorInfo)memberInfo).DeclaringType; } throw new InvalidOperationException(); } public static bool IsFloatType(Type type) { if (IsNullableType(type)) type = type.GetGenericArguments()[0]; switch (Type.GetTypeCode(type)) { case TypeCode.Single : case TypeCode.Double : case TypeCode.Decimal : return true; } return false; } public static bool IsIntegerType(Type type) { if (IsNullableType(type)) type = type.GetGenericArguments()[0]; switch (Type.GetTypeCode(type)) { case TypeCode.SByte : case TypeCode.Byte : case TypeCode.Int16 : case TypeCode.UInt16 : case TypeCode.Int32 : case TypeCode.UInt32 : case TypeCode.Int64 : case TypeCode.UInt64 : return true; } return false; } public static bool IsNullableValueMember(MemberInfo member) { return member.Name == "Value" && member.DeclaringType.IsGenericType && member.DeclaringType.GetGenericTypeDefinition() == typeof(Nullable<>); } public static bool IsNullableHasValueMember(MemberInfo member) { return member.Name == "HasValue" && member.DeclaringType.IsGenericType && member.DeclaringType.GetGenericTypeDefinition() == typeof(Nullable<>); } public static bool Equals(MemberInfo member1, MemberInfo member2) { return Equals(member1, member2, null); } public static bool Equals(MemberInfo member1, MemberInfo member2, Type declaringType) { if (ReferenceEquals(member1, member2)) return true; if (member1 == null || member2 == null) return false; if (member1.Name == member2.Name) { if (member1.DeclaringType == member2.DeclaringType) return true; if (member1 is PropertyInfo) { var isSubclass = IsSameOrParent(member1.DeclaringType, member2.DeclaringType) || IsSameOrParent(member2.DeclaringType, member1.DeclaringType); if (isSubclass) return true; if (declaringType != null && member2.DeclaringType.IsInterface) { var getter1 = ((PropertyInfo)member1).GetGetMethod(); var getter2 = ((PropertyInfo)member2).GetGetMethod(); var map = declaringType.GetInterfaceMap(member2.DeclaringType); for (var i = 0; i < map.InterfaceMethods.Length; i++) if (getter2.Name == map.InterfaceMethods[i].Name && getter2.DeclaringType == map.InterfaceMethods[i].DeclaringType && getter1.Name == map.TargetMethods [i].Name && getter1.DeclaringType == map.TargetMethods [i].DeclaringType) return true; } } } if (member2.DeclaringType.IsInterface && member1.Name.EndsWith(member2.Name)) { if (member1 is PropertyInfo) { var isSubclass = member2.DeclaringType.IsAssignableFrom(member1.DeclaringType); if (isSubclass) { var getter1 = ((PropertyInfo)member1).GetGetMethod(); var getter2 = ((PropertyInfo)member2).GetGetMethod(); var map = member1.DeclaringType.GetInterfaceMap(member2.DeclaringType); for (var i = 0; i < map.InterfaceMethods.Length; i++) if ((getter2 == null || (getter2.Name == map.InterfaceMethods[i].Name && getter2.DeclaringType == map.InterfaceMethods[i].DeclaringType)) && (getter1 == null || (getter1.Name == map.InterfaceMethods[i].Name && getter1.DeclaringType == map.InterfaceMethods[i].DeclaringType)) ) { return true; } } } } return false; } interface IGetDefaultValueHelper { object GetDefaultValue(); } class GetDefaultValueHelper<T> : IGetDefaultValueHelper { public object GetDefaultValue() { return default(T); } } public static object GetDefaultValue(Type type) { var dtype = typeof(GetDefaultValueHelper<>).MakeGenericType(type); var helper = (IGetDefaultValueHelper)Activator.CreateInstance(dtype); return helper.GetDefaultValue(); } #endregion } }