Mercurial > pub > bltoolkit
diff Source/Reflection/TypeHelper.cs @ 0:f990fcb411a9
Копия текущей версии из github
author | cin |
---|---|
date | Thu, 27 Mar 2014 21:46:09 +0400 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Source/Reflection/TypeHelper.cs Thu Mar 27 21:46:09 2014 +0400 @@ -0,0 +1,1692 @@ +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 + } +}