/// <summary> /// Gets the field identified by <paramref name="name"/> on the given <paramref name="type"/>. /// Use the <paramref name="bindingFlags"/> parameter to define the scope of the search. /// </summary> /// <returns>A single FieldInfo instance of the first found match or null if no match was found.</returns> public static FieldInfo Field(this Type type, string name, Flags bindingFlags) { // we need to check all fields to do partial name matches if (bindingFlags.IsAnySet(Flags.PartialNameMatch | Flags.TrimExplicitlyImplemented)) { return(type.Fields(bindingFlags, name).FirstOrDefault()); } var result = type.GetTypeInfo().GetField(name, bindingFlags); if (result == null && bindingFlags.IsNotSet(Flags.DeclaredOnly)) { if (type.GetTypeInfo().BaseType != typeof(object) && type.GetTypeInfo().BaseType != null) { return(type.GetTypeInfo().BaseType.Field(name, bindingFlags)); } } bool hasSpecialFlags = bindingFlags.IsAnySet(Flags.ExcludeBackingMembers | Flags.ExcludeExplicitlyImplemented | Flags.ExcludeHiddenMembers); if (hasSpecialFlags) { IList <FieldInfo> fields = new List <FieldInfo> { result }; fields = fields.Filter(bindingFlags); return(fields.Count > 0 ? fields[0] : null); } return(result); }
/// <summary> /// Gets the method with the given <paramref name="name"/> and matching <paramref name="bindingFlags"/> /// on the given <paramref name="type"/> where the parameter types correspond in order with the /// supplied <paramref name="parameterTypes"/>. /// </summary> /// <param name="type">The type on which to reflect.</param> /// <param name="genericTypes">Type parameters if this is a generic method.</param> /// <param name="name">The name of the method to search for. This argument must be supplied. The /// default behavior is to check for an exact, case-sensitive match. Pass <see href="Flags.ExplicitNameMatch"/> /// to include explicitly implemented interface members, <see href="Flags.PartialNameMatch"/> to locate /// by substring, and <see href="Flags.IgnoreCase"/> to ignore case.</param> /// <param name="parameterTypes">If this parameter is supplied then only methods with the same parameter signature /// will be included in the result. The default behavior is to check only for assignment compatibility, /// but this can be changed to exact matching by passing <see href="Flags.ExactBinding"/>.</param> /// <param name="bindingFlags">The <see cref="BindingFlags"/> or <see cref="Flags"/> combination used to define /// the search behavior and result filtering.</param> /// <returns>The specified method or null if no method was found. If there are multiple matches /// due to method overloading the first found match will be returned.</returns> public static MethodInfo Method(this Type type, Type[] genericTypes, string name, Type[] parameterTypes, Flags bindingFlags) { bool hasTypes = parameterTypes != null; bool hasGenericTypes = genericTypes != null && genericTypes.Length > 0; // we need to check all methods to do partial name matches or complex parameter binding bool processAll = bindingFlags.IsAnySet(Flags.PartialNameMatch | Flags.TrimExplicitlyImplemented); processAll |= hasTypes && bindingFlags.IsSet(Flags.IgnoreParameterModifiers); processAll |= hasGenericTypes; if (processAll) { return(type.Methods(genericTypes, parameterTypes, bindingFlags, name).FirstOrDefault().MakeGeneric(genericTypes)); } var result = hasTypes ? type.GetMethod(name, bindingFlags, null, parameterTypes, null) : type.GetMethod(name, bindingFlags); if (result == null && bindingFlags.IsNotSet(Flags.DeclaredOnly)) { if (type.BaseType != typeof(object) && type.BaseType != null) { return(type.BaseType.Method(name, parameterTypes, bindingFlags).MakeGeneric(genericTypes)); } } bool hasSpecialFlags = bindingFlags.IsAnySet(Flags.ExcludeBackingMembers | Flags.ExcludeExplicitlyImplemented | Flags.ExcludeHiddenMembers); if (hasSpecialFlags) { var methods = new List <MethodInfo> { result }.Filter(bindingFlags); return((methods.Count > 0 ? methods[0] : null).MakeGeneric(genericTypes)); } return(result.MakeGeneric(genericTypes)); }
/// <summary> /// Gets the method with the given <paramref name="name"/> and matching <paramref name="bindingFlags"/> /// on the given <paramref name="type"/> where the parameter types correspond in order with the /// supplied <paramref name="parameterTypes"/>. /// </summary> /// <param name="type">The type on which to reflect.</param> /// <param name="genericTypes">Type parameters if this is a generic method.</param> /// <param name="name">The name of the method to search for. This argument must be supplied. The /// default behavior is to check for an exact, case-sensitive match. Pass <see href="Flags.ExplicitNameMatch"/> /// to include explicitly implemented interface members, <see href="Flags.PartialNameMatch"/> to locate /// by substring, and <see href="Flags.IgnoreCase"/> to ignore case.</param> /// <param name="parameterTypes">If this parameter is supplied then only methods with the same parameter signature /// will be included in the result. The default behavior is to check only for assignment compatibility, /// but this can be changed to exact matching by passing <see href="Flags.ExactBinding"/>.</param> /// <param name="bindingFlags">The <see cref="BindingFlags"/> or <see cref="Flags"/> combination used to define /// the search behavior and result filtering.</param> /// <returns>The specified method or null if no method was found. If there are multiple matches /// due to method overloading the first found match will be returned.</returns> public static MethodInfo Method(this Type type, Type[] genericTypes, string name, Type[] parameterTypes, Flags bindingFlags) { bool hasTypes = parameterTypes != null; bool hasGenericTypes = genericTypes != null && genericTypes.Length > 0; // we need to check all methods to do partial name matches or complex parameter binding bool processAll = bindingFlags.IsAnySet(Flags.PartialNameMatch | Flags.TrimExplicitlyImplemented); processAll |= hasTypes && bindingFlags.IsSet(Flags.IgnoreParameterModifiers); processAll |= hasGenericTypes; if (processAll) { //TODO: Might have to do the same polymorphic parameter type check for generics return(type.Methods(genericTypes, parameterTypes, bindingFlags, name).FirstOrDefault().MakeGeneric(genericTypes)); } //TODO: Check fasterflect cache first //TODO: Find out why we needed to call HasParameterSignature for polymorphism var result = hasTypes ? type.GetTypeInfo().GetMethods(bindingFlags).FirstOrDefault(mi => mi.Name == name && mi.HasParameterSignature(parameterTypes)) : type.GetTypeInfo().GetMethod(name, bindingFlags); if (result == null && bindingFlags.IsNotSet(Flags.DeclaredOnly)) { if (type.GetTypeInfo().BaseType != typeof(object) && type.GetTypeInfo().BaseType != null) { //TODO: Added slow polymorphic type checking //TODO: Check fasterflect cache first if (hasTypes) { return(type.GetTypeInfo().BaseType.GetTypeInfo().GetMethods(bindingFlags).FirstOrDefault(mi => mi.Name == name && mi.HasParameterSignature(parameterTypes))); } else { return(type.GetTypeInfo().BaseType.Method(name, parameterTypes, bindingFlags)); } } } bool hasSpecialFlags = bindingFlags.IsAnySet(Flags.ExcludeBackingMembers | Flags.ExcludeExplicitlyImplemented | Flags.ExcludeHiddenMembers); if (hasSpecialFlags) { var methods = new List <MethodInfo> { result }.Filter(bindingFlags); return((methods.Count > 0 ? methods[0] : null).MakeGeneric(genericTypes)); } return(result.MakeGeneric(genericTypes)); }
/// <summary> /// Gets the property identified by <paramref name="name"/> on the given <paramref name="type"/>. /// Use the <paramref name="bindingFlags"/> parameter to define the scope of the search. /// </summary> /// <returns>A single PropertyInfo instance of the first found match or null if no match was found.</returns> public static PropertyInfo Property(this Type type, string name, Flags bindingFlags) { // we need to check all properties to do partial name matches if (bindingFlags.IsAnySet(Flags.PartialNameMatch | Flags.TrimExplicitlyImplemented)) { return(type.Properties(bindingFlags, name).FirstOrDefault()); } var result = type.GetTypeInfo().GetProperty(name, bindingFlags | Flags.DeclaredOnly); if (result == null && bindingFlags.IsNotSet(Flags.DeclaredOnly)) { if (type.GetTypeInfo().BaseType != typeof(object) && type.GetTypeInfo().BaseType != null) { return(type.GetTypeInfo().BaseType.Property(name, bindingFlags)); } } bool hasSpecialFlags = bindingFlags.IsSet(Flags.ExcludeExplicitlyImplemented); if (hasSpecialFlags) { IList <PropertyInfo> properties = new List <PropertyInfo> { result }; properties = properties.Filter(bindingFlags); return(properties.Count > 0 ? properties[0] : null); } return(result); }
/// <summary> /// Gets all methods on the given <paramref name="type"/> that match the given lookup criteria. /// </summary> /// <param name="type">The type on which to reflect.</param> /// <param name="genericTypes">If this parameter is supplied then only methods with the same generic parameter /// signature will be included in the result. The default behavior is to check only for assignment compatibility, /// but this can be changed to exact matching by passing <see href="Flags.ExactBinding"/>.</param> /// <param name="parameterTypes">If this parameter is supplied then only methods with the same parameter signature /// will be included in the result. The default behavior is to check only for assignment compatibility, /// but this can be changed to exact matching by passing <see href="Flags.ExactBinding"/>.</param> /// <param name="bindingFlags">The <see cref="BindingFlags"/> or <see cref="Flags"/> combination used to define /// the search behavior and result filtering.</param> /// <param name="names">The optional list of names against which to filter the result. If this parameter is /// <c>null</c> or empty no name filtering will be applied. The default behavior is to check for an exact, /// case-sensitive match. Pass <see href="Flags.ExcludeExplicitlyImplemented"/> to exclude explicitly implemented /// interface members, <see href="Flags.PartialNameMatch"/> to locate by substring, and /// <see href="Flags.IgnoreCase"/> to ignore case.</param> /// <returns>A list of all matching methods. This value will never be null.</returns> public static IList <MethodInfo> Methods(this Type type, Type[] genericTypes, Type[] parameterTypes, Flags bindingFlags, params string[] names) { if (type == null || type == typeof(object)) { return(new MethodInfo[0]); } bool recurse = bindingFlags.IsNotSet(Flags.DeclaredOnly); bool hasNames = names != null && names.Length > 0; bool hasTypes = parameterTypes != null; bool hasGenericTypes = genericTypes != null && genericTypes.Length > 0; bool hasSpecialFlags = bindingFlags.IsAnySet(Flags.ExcludeBackingMembers | Flags.ExcludeExplicitlyImplemented | Flags.ExcludeHiddenMembers); if (!recurse && !hasNames && !hasTypes && !hasSpecialFlags) { return(type.GetMethods(bindingFlags) ?? new MethodInfo[0]); } var methods = GetMethods(type, bindingFlags); methods = hasNames ? methods.Filter(bindingFlags, names) : methods; methods = hasGenericTypes ? methods.Filter(genericTypes) : methods; methods = hasTypes ? methods.Filter(bindingFlags, parameterTypes) : methods; methods = hasSpecialFlags ? methods.Filter(bindingFlags) : methods; return(methods); }
/// <summary> /// Gets the member identified by <paramref name="name"/> on the given <paramref name="type"/>. Use /// the <paramref name="bindingFlags"/> parameter to define the scope of the search. /// </summary> /// <returns>A single MemberInfo instance of the first found match or null if no match was found.</returns> public static MemberInfo Member( this Type type, string name, Flags bindingFlags ) { // we need to check all members to do partial name matches if( bindingFlags.IsAnySet( Flags.PartialNameMatch | Flags.TrimExplicitlyImplemented ) ) { return type.Members( MemberTypes.All, bindingFlags, name ).FirstOrDefault(); } IList<MemberInfo> result = type.GetMember( name, bindingFlags ); bool hasSpecialFlags = bindingFlags.IsAnySet( Flags.ExcludeBackingMembers | Flags.ExcludeExplicitlyImplemented | Flags.ExcludeHiddenMembers ); result = hasSpecialFlags && result.Count > 0 ? result.Filter( bindingFlags ) : result; bool found = result.Count > 0; if( !found && bindingFlags.IsNotSet( Flags.DeclaredOnly ) ) { if( type.BaseType != typeof(object) && type.BaseType != null ) { return type.BaseType.Member( name, bindingFlags ); } } return found ? result[ 0 ] : null; }
/// <summary> /// Gets all properties on the given <paramref name="type"/> that match the specified <paramref name="bindingFlags"/>, /// including properties defined on base types. /// </summary> /// <returns>A list of all matching properties on the type. This value will never be null.</returns> public static IList <PropertyInfo> Properties(this Type type, Flags bindingFlags, params string[] names) { if (type == null || type == Constants.ObjectType) { return(Constants.EmptyPropertyInfoArray); } bool recurse = bindingFlags.IsNotSet(Flags.DeclaredOnly); bool hasNames = names != null && names.Length > 0; bool hasSpecialFlags = bindingFlags.IsAnySet(Flags.ExcludeBackingMembers | Flags.ExcludeExplicitlyImplemented | Flags.ExcludeHiddenMembers); if (!recurse && !hasNames && !hasSpecialFlags) { return(type.GetTypeInfo().GetProperties(bindingFlags) ?? Constants.EmptyPropertyInfoArray); } var properties = GetProperties(type, bindingFlags); properties = hasSpecialFlags ? properties.Filter(bindingFlags) : properties; properties = hasNames ? properties.Filter(bindingFlags, names) : properties; return(properties); }
/// <summary> /// Gets all fields on the given <paramref name="type"/> that match the specified <paramref name="bindingFlags"/>. /// </summary> /// <param name="type">The type on which to reflect.</param> /// <param name="bindingFlags">The <see cref="BindingFlags"/> or <see cref="Flags"/> combination used to define /// the search behavior and result filtering.</param> /// <param name="names">The optional list of names against which to filter the result. If this parameter is /// <c>null</c> or empty no name filtering will be applied. The default behavior is to check for an exact, /// case-sensitive match. Pass <see href="Flags.ExcludeExplicitlyImplemented"/> to exclude explicitly implemented /// interface members, <see href="Flags.PartialNameMatch"/> to locate by substring, and /// <see href="Flags.IgnoreCase"/> to ignore case.</param> /// <returns>A list of all matching fields on the type. This value will never be null.</returns> public static IList <FieldInfo> Fields(this Type type, Flags bindingFlags, params string[] names) { if (type == null || type == typeof(object)) { return(new FieldInfo[0]); } bool recurse = bindingFlags.IsNotSet(Flags.DeclaredOnly); bool hasNames = names != null && names.Length > 0; bool hasSpecialFlags = bindingFlags.IsAnySet(Flags.ExcludeBackingMembers | Flags.ExcludeExplicitlyImplemented | Flags.ExcludeHiddenMembers); if (!recurse && !hasNames && !hasSpecialFlags) { return(type.GetTypeInfo().GetFields(bindingFlags) ?? new FieldInfo[0]); } var fields = GetFields(type, bindingFlags); fields = hasSpecialFlags ? fields.Filter(bindingFlags) : fields; fields = hasNames ? fields.Filter(bindingFlags, names) : fields; return(fields); }
/// <summary> /// Gets all members of the given <paramref name="memberTypes"/> on the given <paramref name="type"/> that /// match the specified <paramref name="bindingFlags"/>, optionally filtered by the supplied <paramref name="names"/> /// list (in accordance with the given <paramref name="bindingFlags"/>). /// </summary> /// <param name="type">The type to reflect on.</param> /// <param name="memberTypes">The <see href="MemberTypes"/> to include in the result.</param> /// <param name="bindingFlags">The <see cref="BindingFlags"/> or <see cref="Flags"/> combination used to define /// the search behavior and result filtering.</param> /// <param name="names">The optional list of names against which to filter the result. If this parameter is /// <c>null</c> or empty no name filtering will be applied. The default behavior is to check for an exact, /// case-sensitive match. Pass <see href="Flags.ExcludeExplicitlyImplemented"/> to exclude explicitly implemented /// interface members, <see href="Flags.PartialNameMatch"/> to locate by substring, and /// <see href="Flags.IgnoreCase"/> to ignore case.</param> /// <returns>A list of all matching members on the type. This value will never be null.</returns> public static IList<MemberInfo> Members( this Type type, MemberTypes memberTypes, Flags bindingFlags, params string[] names) { if( type == null || type == typeof(object) ) { return new MemberInfo[0]; } bool recurse = bindingFlags.IsNotSet( Flags.DeclaredOnly ); bool hasNames = names != null && names.Length > 0; bool hasSpecialFlags = bindingFlags.IsAnySet( Flags.ExcludeBackingMembers | Flags.ExcludeExplicitlyImplemented | Flags.ExcludeHiddenMembers ); if( ! recurse && ! hasNames && ! hasSpecialFlags ) { return type.FindMembers( memberTypes, bindingFlags, null, null ); } var members = GetMembers( type, memberTypes, bindingFlags ); members = hasSpecialFlags ? members.Filter( bindingFlags ) : members; members = hasNames ? members.Filter( bindingFlags, names ) : members; return members; }
/// <summary> /// Gets the field identified by <paramref name="name"/> on the given <paramref name="type"/>. /// Use the <paramref name="bindingFlags"/> parameter to define the scope of the search. /// </summary> /// <returns>A single FieldInfo instance of the first found match or null if no match was found.</returns> public static FieldInfo Field( this Type type, string name, Flags bindingFlags ) { // we need to check all fields to do partial name matches if( bindingFlags.IsAnySet( Flags.PartialNameMatch | Flags.TrimExplicitlyImplemented ) ) { return type.Fields( bindingFlags, name ).FirstOrDefault(); } var result = type.GetField( name, bindingFlags ); if( result == null && bindingFlags.IsNotSet( Flags.DeclaredOnly ) ) { if( type.BaseType != typeof(object) && type.BaseType != null ) { return type.BaseType.Field( name, bindingFlags ); } } bool hasSpecialFlags = bindingFlags.IsAnySet( Flags.ExcludeBackingMembers | Flags.ExcludeExplicitlyImplemented | Flags.ExcludeHiddenMembers ); if( hasSpecialFlags ) { IList<FieldInfo> fields = new List<FieldInfo> { result }; fields = fields.Filter( bindingFlags ); return fields.Count > 0 ? fields[ 0 ] : null; } return result; }
/// <summary> /// Gets all fields on the given <paramref name="type"/> that match the specified <paramref name="bindingFlags"/>. /// </summary> /// <param name="type">The type on which to reflect.</param> /// <param name="bindingFlags">The <see cref="BindingFlags"/> or <see cref="Flags"/> combination used to define /// the search behavior and result filtering.</param> /// <param name="names">The optional list of names against which to filter the result. If this parameter is /// <c>null</c> or empty no name filtering will be applied. The default behavior is to check for an exact, /// case-sensitive match. Pass <see href="Flags.ExcludeExplicitlyImplemented"/> to exclude explicitly implemented /// interface members, <see href="Flags.PartialNameMatch"/> to locate by substring, and /// <see href="Flags.IgnoreCase"/> to ignore case.</param> /// <returns>A list of all matching fields on the type. This value will never be null.</returns> public static IList<FieldInfo> Fields( this Type type, Flags bindingFlags, params string[] names ) { if( type == null || type == typeof(object) ) { return new FieldInfo[0]; } bool recurse = bindingFlags.IsNotSet( Flags.DeclaredOnly ); bool hasNames = names != null && names.Length > 0; bool hasSpecialFlags = bindingFlags.IsAnySet( Flags.ExcludeBackingMembers | Flags.ExcludeExplicitlyImplemented | Flags.ExcludeHiddenMembers ); if( ! recurse && ! hasNames && ! hasSpecialFlags ) { return type.GetFields( bindingFlags ) ?? new FieldInfo[0]; } var fields = GetFields( type, bindingFlags ); fields = hasSpecialFlags ? fields.Filter( bindingFlags ) : fields; fields = hasNames ? fields.Filter( bindingFlags, names ) : fields; return fields; }
/// <summary> /// Gets the property identified by <paramref name="name"/> on the given <paramref name="type"/>. /// Use the <paramref name="bindingFlags"/> parameter to define the scope of the search. /// </summary> /// <returns>A single PropertyInfo instance of the first found match or null if no match was found.</returns> public static PropertyInfo Property( this Type type, string name, Flags bindingFlags ) { // we need to check all properties to do partial name matches if( bindingFlags.IsAnySet( Flags.PartialNameMatch | Flags.TrimExplicitlyImplemented ) ) { return type.Properties( bindingFlags, name ).FirstOrDefault(); } var result = type.GetProperty( name, bindingFlags | Flags.DeclaredOnly ); if( result == null && bindingFlags.IsNotSet( Flags.DeclaredOnly ) ) { if( type.BaseType != typeof(object) && type.BaseType != null ) { return type.BaseType.Property( name, bindingFlags ); } } bool hasSpecialFlags = bindingFlags.IsSet( Flags.ExcludeExplicitlyImplemented ); if( hasSpecialFlags ) { IList<PropertyInfo> properties = new List<PropertyInfo> { result }; properties = properties.Filter( bindingFlags ); return properties.Count > 0 ? properties[ 0 ] : null; } return result; }
/// <summary> /// Gets all properties on the given <paramref name="type"/> that match the specified <paramref name="bindingFlags"/>, /// including properties defined on base types. /// </summary> /// <returns>A list of all matching properties on the type. This value will never be null.</returns> public static IList<PropertyInfo> Properties( this Type type, Flags bindingFlags, params string[] names ) { if (type == null || type == Constants.ObjectType) { return Constants.EmptyPropertyInfoArray; } bool recurse = bindingFlags.IsNotSet( Flags.DeclaredOnly ); bool hasNames = names != null && names.Length > 0; bool hasSpecialFlags = bindingFlags.IsAnySet( Flags.ExcludeBackingMembers | Flags.ExcludeExplicitlyImplemented | Flags.ExcludeHiddenMembers ); if( ! recurse && ! hasNames && ! hasSpecialFlags ) { return type.GetProperties( bindingFlags ) ?? Constants.EmptyPropertyInfoArray; } var properties = GetProperties( type, bindingFlags ); properties = hasSpecialFlags ? properties.Filter( bindingFlags ) : properties; properties = hasNames ? properties.Filter( bindingFlags, names ) : properties; return properties; }
/// <summary> /// Gets all members of the given <paramref name="memberTypes"/> on the given <paramref name="type"/> that /// match the specified <paramref name="bindingFlags"/>, optionally filtered by the supplied <paramref name="names"/> /// list (in accordance with the given <paramref name="bindingFlags"/>). /// </summary> /// <param name="type">The type to reflect on.</param> /// <param name="memberTypes">The <see href="MemberTypes"/> to include in the result.</param> /// <param name="bindingFlags">The <see cref="BindingFlags"/> or <see cref="Flags"/> combination used to define /// the search behavior and result filtering.</param> /// <param name="names">The optional list of names against which to filter the result. If this parameter is /// <c>null</c> or empty no name filtering will be applied. The default behavior is to check for an exact, /// case-sensitive match. Pass <see href="Flags.ExcludeExplicitlyImplemented"/> to exclude explicitly implemented /// interface members, <see href="Flags.PartialNameMatch"/> to locate by substring, and /// <see href="Flags.IgnoreCase"/> to ignore case.</param> /// <returns>A list of all matching members on the type. This value will never be null.</returns> public static IList<MemberInfo> Members( this Type type, MemberTypes memberTypes, Flags bindingFlags, params string[] names ) { if( type == null || type == typeof(object) ) { return new MemberInfo[0]; } bool recurse = bindingFlags.IsNotSet( Flags.DeclaredOnly ); bool hasNames = names != null && names.Length > 0; bool hasSpecialFlags = bindingFlags.IsAnySet( Flags.ExcludeBackingMembers | Flags.ExcludeExplicitlyImplemented | Flags.ExcludeHiddenMembers ); if( ! recurse && ! hasNames && ! hasSpecialFlags ) { return type.FindMembers( memberTypes, bindingFlags, null, null ); } var members = GetMembers( type, memberTypes, bindingFlags ); members = hasSpecialFlags ? members.Filter( bindingFlags ) : members; members = hasNames ? members.Filter( bindingFlags, names ) : members; return members; }
/// <summary> /// Gets the method with the given <paramref name="name"/> and matching <paramref name="bindingFlags"/> /// on the given <paramref name="type"/> where the parameter types correspond in order with the /// supplied <paramref name="parameterTypes"/>. /// </summary> /// <param name="type">The type on which to reflect.</param> /// <param name="genericTypes">Type parameters if this is a generic method.</param> /// <param name="name">The name of the method to search for. This argument must be supplied. The /// default behavior is to check for an exact, case-sensitive match. Pass <see href="Flags.ExplicitNameMatch"/> /// to include explicitly implemented interface members, <see href="Flags.PartialNameMatch"/> to locate /// by substring, and <see href="Flags.IgnoreCase"/> to ignore case.</param> /// <param name="parameterTypes">If this parameter is supplied then only methods with the same parameter signature /// will be included in the result. The default behavior is to check only for assignment compatibility, /// but this can be changed to exact matching by passing <see href="Flags.ExactBinding"/>.</param> /// <param name="bindingFlags">The <see cref="BindingFlags"/> or <see cref="Flags"/> combination used to define /// the search behavior and result filtering.</param> /// <returns>The specified method or null if no method was found. If there are multiple matches /// due to method overloading the first found match will be returned.</returns> public static MethodInfo Method( this Type type, Type[] genericTypes, string name, Type[] parameterTypes, Flags bindingFlags ) { bool hasTypes = parameterTypes != null; bool hasGenericTypes = genericTypes != null && genericTypes.Length > 0; // we need to check all methods to do partial name matches or complex parameter binding bool processAll = bindingFlags.IsAnySet( Flags.PartialNameMatch | Flags.TrimExplicitlyImplemented ); processAll |= hasTypes && bindingFlags.IsSet( Flags.IgnoreParameterModifiers ); processAll |= hasGenericTypes; if( processAll ) { return type.Methods( genericTypes, parameterTypes, bindingFlags, name ).FirstOrDefault().MakeGeneric( genericTypes ); } var result = hasTypes ? type.GetMethod( name, bindingFlags, null, parameterTypes, null ) : type.GetMethod( name, bindingFlags ); if( result == null && bindingFlags.IsNotSet( Flags.DeclaredOnly ) ) { if( type.BaseType != typeof(object) && type.BaseType != null ) { return type.BaseType.Method( name, parameterTypes, bindingFlags ).MakeGeneric( genericTypes ); } } bool hasSpecialFlags = bindingFlags.IsAnySet( Flags.ExcludeBackingMembers | Flags.ExcludeExplicitlyImplemented | Flags.ExcludeHiddenMembers ); if( hasSpecialFlags ) { var methods = new List<MethodInfo> { result }.Filter( bindingFlags ); return (methods.Count > 0 ? methods[ 0 ] : null).MakeGeneric( genericTypes ); } return result.MakeGeneric(genericTypes); }