How to Get Methods with C# Reflection
c# reflection get methods: Learn how to retrieve method metadata using C# reflection, filter with BindingFlags, handle overloads, and avoid common performance pitfalls.
When you need to inspect the methods of a type at runtime, c# reflection get methods is the core operation. The System.Type class exposes two primary APIs: GetMethods() returns an array of all matching MethodInfo objects, while GetMethod(string name) finds a single method by name. Both are part of System.Reflection and give you access to metadata such as parameters, return types, and custom attributes without knowing the type at compile time.
The Core API for Retrieving Methods
The simplest call is typeof(MyClass).GetMethods(), which returns all public instance and static methods declared on the type, including inherited public methods. For a more controlled search, GetMethod(string name) returns the first public method that matches the name, but it throws AmbiguousMatchException if there are multiple overloads. To avoid that, you must provide parameter types or use GetMethods() and filter manually.
using System; using System.Reflection; public class Sample { public void DoWork() { } public void DoWork(int value) { } private void Helper() { } } Type type = typeof(Sample); MethodInfo[] allPublic = type.GetMethods(); foreach (var method in allPublic) { Console.WriteLine(method.Name); }
This code prints DoWork, DoWork, ToString, Equals, GetHashCode, and GetType because GetMethods() without flags includes inherited public methods. The private Helper is not included. If you need only methods declared on the type itself, you must use BindingFlags.DeclaredOnly.
Filtering Methods with BindingFlags
BindingFlags gives you precise control over which methods are returned. The most common combinations are:
BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static– the default when you callGetMethods()with no flags.BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static– to include private, protected, and internal methods.BindingFlags.DeclaredOnly– to exclude inherited members.
For example, to get only private instance methods declared on the type:
MethodInfo[] privateMethods = type.GetMethods( BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
This returns only Helper. Remember that BindingFlags requires you to specify Instance or Static explicitly; otherwise, no methods are returned. A common mistake is to pass only Public without Instance or Static, which results in an empty array.
Working with MethodInfo: Invocation and Metadata
Once you have a MethodInfo, you can inspect its parameters, return type, and attributes, or invoke it. Invocation is done with Invoke(object obj, object[] parameters), where obj is the target instance for instance methods or null for static methods. The parameters array must match the method signature exactly.
MethodInfo method = type.GetMethod("DoWork", new[] { typeof(int) }); object instance = Activator.CreateInstance(type); method.Invoke(instance, new object[] { 42 });
GetMethod with a parameter type array resolves the overload unambiguously. This is safer than calling GetMethod("DoWork") alone, which throws if multiple overloads exist. The returned MethodInfo also exposes ReturnType, GetParameters(), and GetCustomAttributes(), which are useful for building tools like serializers or dependency injection containers.
Performance and Caching Considerations
Reflection is significantly slower than direct method calls because it involves metadata lookup, argument array allocation, and runtime type checks. In hot paths, repeated calls to GetMethods() or GetMethod() can become a bottleneck. The typical mitigation is to cache the MethodInfo objects after the first lookup. For example, a static dictionary keyed by type and method name can store the resolved MethodInfo for reuse.
private static readonly Dictionary<string, MethodInfo> Cache = new(); public static MethodInfo GetCachedMethod(Type type, string name) { string key = type.FullName + "." + name; if (!Cache.TryGetValue(key, out var method)) { method = type.GetMethod(name); Cache[key] = method; } return method; }
Even with caching, invoking a MethodInfo remains slower than a direct delegate. If you need repeated invocation, consider converting the MethodInfo to a strongly typed delegate using Delegate.CreateDelegate or building an expression tree. This moves the reflection cost to the setup phase and gives you near-direct call performance afterward.
Handling Overloads and Generic Methods
Overload resolution is a common source of confusion. GetMethod(string name) throws AmbiguousMatchException when multiple methods share the name. To select a specific overload, pass an array of parameter types, as shown earlier. For generic methods, the situation is more complex. GetMethod("MyGeneric") returns the open generic method definition, not a constructed version. To get a closed generic method, you must call MakeGenericMethod with the desired type arguments.
MethodInfo openMethod = typeof(GenericSample).GetMethod("Process"); MethodInfo closedMethod = openMethod.MakeGenericMethod(typeof(string));
This works because GetMethod returns the generic method definition when the name matches. If you need to find a generic method with specific constraints, you may have to iterate over all methods and check IsGenericMethodDefinition and GetGenericArguments().
Common Pitfalls and Edge Cases
Several edge cases can trip up even experienced developers. First, GetMethods() returns methods in a non-deterministic order; do not rely on the array order. Second, inherited methods are included by default, which can cause unexpected results when you filter by name. Use DeclaredOnly to restrict to the type itself. Third, GetMethod can return null if no matching method exists, so always check for null before invoking. Finally, accessing non-public methods requires full trust in .NET Framework; in .NET Core and .NET 5+, reflection restrictions are less strict, but the method must be accessible in the security context.
Another subtle issue is that GetMethods() returns methods from interfaces implemented by the type, but only if they are publicly visible. For explicit interface implementations, the method is private and requires NonPublic flag to retrieve.
When to Use Reflection vs. Alternatives
Reflection is the right tool when you need runtime type discovery that cannot be done at compile time, such as building a plugin system, a serializer, or an ORM. However, if you know the method signature at compile time, prefer a delegate or an interface. For scenarios where you need to invoke a method by name but the set of methods is fixed, consider using a Dictionary<string, Delegate> to map names to delegates, avoiding reflection entirely.
Use GetMethods() when you need to enumerate all methods for analysis, such as in a documentation generator. Use GetMethod() when you need a single known method and can provide parameter types to avoid ambiguity. The decision ultimately depends on whether the type is known at compile time and whether the overhead of reflection is acceptable for your performance requirements.