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