Multiple ways to figure out User-Defined Methods from a Class using Reflection

Rajnilari2015
Posted by in C# category on for Intermediate level | Points: 250 | Views : 3948 red flag
Rating: 4.5 out of 5  
 2 vote(s)

In this article, we will look into how can we figure out only User Defined Methods from a Class using Reflection.


 Download source code for Multiple ways to figure out User-Defined Methods from a Class using Reflection

Introduction

If we want to glean the information about a class or Assembly at runtime,to add properties/methods etc. to the class/assembly at runtime or dynamically,the only way to perform this is the Reflection mechanism. In dotnet, we use the System.Reflection namespace which contains all the needed methods for achieving the work. In this article, we will look into how can we figure out only User-Defined Methods from a Class using Reflection.

Initial Setup

First of all, let us create a class as under

public class Employee
{
    public int EmployeeId { get; set; }
    public string EmployeeName { get; set; }

    public void Display()
    {
        Console.WriteLine("{0} {1}", EmployeeId, EmployeeName);
    }
    public string DisplayFormattedMesage(string message)
    {
        return string.Concat(message, " ", EmployeeName);
    }
    private int GetEmployeeID()
    {
        return EmployeeId;           
    }

    private static int GetStaticEmployeeID()
    {
        return 123456;
    }  

    [DllImport("kernel32.dll")]
    public static extern bool AnExternMethod(int ferequency, int duration);       
}

Using the code

As can be figure out that, it is a typical class that we encounter almost every day , with two properties namely EmployeeId and EmployeeName and a few methods some are public, private, static and extern. Now let us execute the below program.


using System;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        { 
       //Get all the public,private, static and instance members of the Employee class using the        //GetMethods of using System.Reflection
            var methodInfos = typeof(Employee).GetMethods(
                                                            BindingFlags.Public |
                                                            BindingFlags.NonPublic |
                                                            BindingFlags.Instance |
                                                            BindingFlags.Static
                                                          ).ToList();

            //print the methods
            foreach (var methodInfo in methodInfos) Console.WriteLine(methodInfo.Name);

            Console.Read();
        }
    }
}

The result

But our intention is to get only the user-defined methods.So let's see how it can be achieve.Before going to write the program segment, lets look into the System.Object class.

We can figure out that Equals,GetHashCode and ToString are virtual.We can eliminate them easily by putting a filtering condition by using the read-only property IsVirtual of the MethodBase class.

The IsVirtual states :

foreach (var methodInfo in methodInfos)
{
    if (!methodInfo.IsVirtual) //eliminate the Virtual Methods of the System.Object
    	Console.WriteLine(methodInfo.Name);
}

The result

Now we are left with GetType and MemberwiseClone. There is a read-only property under MethodBase class by the name MethodImplementationFlags. It

Gets the System.Reflection.MethodImplAttributes flags that specify the attributes of a method implementation.

The MethodImplAttributes is an Enum that specifies flags for the attributes of a method implementation.

For the case of GetType and MemberwiseClone, the MethodImplementationFlags is of the MethodImplAttributes Enum InternalCall. Hence, the below will do the work

//print the methods
foreach (var methodInfo in methodInfos)
{
    if (!methodInfo.IsVirtual)
    {
        if (methodInfo.MethodImplementationFlags != MethodImplAttributes.InternalCall)
            Console.WriteLine(methodInfo.Name);
    }
}

Now we need to eliminate the getter and setter properties.Before going to say anything, we would like to show what the IL says

Double click on get_EmployeeId:int32() and we will find

Observe the SpecialName bit - It indicates that the method is special. So,in this case, there is a property call IsSpecialName, which is set to True. The trick is to filter out those methods where the IsSpecialName is "False"

//print the methods
foreach (var methodInfo in methodInfos)
{
    //eliminate the virtual methods of the System.Object class
    if (!methodInfo.IsVirtual) 
    {
        //eliminate the InternalCall of the System.Object class
        if (methodInfo.MethodImplementationFlags != MethodImplAttributes.InternalCall)
        {
            //eliminate the SpecialNames methods like properties
            if (!methodInfo.IsSpecialName)
            {
                Console.WriteLine(methodInfo.Name);
            }
        }
    }
}

And here we go

So we achieve our target.Below is a lambda version of the same

 //The lambda version
	methodInfos
	.Where(m => !m.IsSpecialName && !m.IsVirtual && m.MethodImplementationFlags != MethodImplAttributes.InternalCall)
	.ToList()
	.ForEach(i => Console.WriteLine(i.Name));

But is it the only way? Cannot it be done in a much better way? Yes - of-course! The BindingFlags has a member DeclaredOnly. It says

Specifies that only members declared at the level of the supplied type's hierarchy should be considered. Inherited members are not considered.

So let us modify our program as under

typeof(Employee)                
.GetMethods(
             BindingFlags.Public |
             BindingFlags.NonPublic |
             BindingFlags.Instance |
             BindingFlags.Static | 
             BindingFlags.DeclaredOnly
           )

.ToList()
.ForEach(i => Console.WriteLine(i.Name));

The output

Now we know what to do

typeof(Employee)                
.GetMethods(
             BindingFlags.Public |
             BindingFlags.NonPublic |
             BindingFlags.Instance |
             BindingFlags.Static | 
             BindingFlags.DeclaredOnly
           )
.Where(m => !m.IsSpecialName )               
.ToList()
.ForEach(i => Console.WriteLine(i.Name));

References

Reflection in C# Tutorial

Conclusion

Hope you will find this useful.Thanks for reading the article.Please find the zipped file attached herewith.

Page copy protected against web site content infringement by Copyscape

About the Author

Rajnilari2015
Full Name: Niladri Biswas (RNA Team)
Member Level: Platinum
Member Status: Member,Microsoft_MVP,MVP
Member Since: 3/17/2015 2:41:06 AM
Country: India
-- Thanks & Regards, RNA Team


Login to vote for this post.

Comments or Responses

Login to post response

Comment using Facebook(Author doesn't get notification)