Click here to Skip to main content
15,885,546 members
Articles / Programming Languages / C#

LINQing the Reflection

Rate me:
Please Sign up or sign in to vote.
3.95/5 (11 votes)
15 Sep 2009CPOL2 min read 29.9K   99   12   8
Using LINQ with reflection with minimum coding to access the members dynamically

Introduction

Using Reflection at runtime is a bit complex and accessing objects by iterating through Collection takes time. I tried to use LINQ to object to simplify this process as much as possible.

In the sample given here, I explain two scenarios of using Reflection:

  1. Dynamically getting the count of Property of specific Type in an object
  2. Dynamically loading an overloaded method

The illustration in the code has both classic methods and methods using LINQ.

Using the Code

I'm going to use the below object to demonstrate the logic.

A simple object is used here for simplicity of code.

Object consists of nine properties and two methods overloaded into the objects:

C#
public class person 
{
    public string name { get; set; } 
    public string Address { get; set; }
    public string URL { get; set; } 
    public string City { get; set; }
    public int pincode { get; set; } 
    public int Age { get; set; } 
    public int Height { get; set; }
    public DateTime DOB { get; set; }
    public string street { get; set; }

public string myMethod(int i)
    {
    return "This invoke method with single Parameter";
    }

public string myMethod(int i, string j)
    {
    return "This invoke method with double Parameter";
    }
}

The requirement here is to display the count of string attributes for object dynamically.

Initially, reflection is used to achieve this by iterating through the Propertyinfo collection.

C#
private static int StringMemeberCountClassic<T>(this T source) where T : class 
    { 
        //use Propertyinfo collection to get the Count of String Member 
        int iret; iret = 0; PropertyInfo[] oProp = source.GetType().GetProperties(); 
        foreach (PropertyInfo prop in oProp) 
            { 
                if (prop.PropertyType.Name == "String") 
                    { iret++; } 
            } 
        return iret;
     }

This works fine, but I feel this code can be improved to an extent.

I thought of using LINQ to object query to reduce the looping and create method. I also created another method that will return the count of attributes not of type string.

C#
     /// Extension Method to Count number of String Member .
private static int StringMemeberCount<t>(this T source) where T : class 
    { 
    //use LINQ to get the Count of String Member 
    int iret = (from a in source.GetType().GetProperties() 
             where a.PropertyType.Name == "String" 
             select a).Count(); 
    return iret; 
    } 
    /// <summary>/// Extension Method to Count number of non String Member. 
  private static int nonStringMemeberCount<t>(this T source) where T : class
     { 
    //use LINQ to get the Count of String Member 
        int iret = (from a in source.GetType().GetProperties() 
        where a.PropertyType.Name != "String" 
        select a).Count(); 
        return iret;
     }

Secondly, there is a requirement to load the method dynamically. I used a custom way of doing this as shown below. When the code is executed, it throws an exception as ambiguous match found. Unfortunately this was an overloaded method:

C#
private static string overloadCallClassic<T>(T source, int param) where T : class 
{
MethodInfo mi = source.GetType().GetMethod("myMethod");
if (param == 1)
 { 
    object[] arguments = { 1 }; 
    return mi.Invoke(source, arguments).ToString();
  }
if (param == 2)
  { 
     object[] arguments = { 1, "abz" }; 
    return mi.Invoke(source, arguments).ToString();
  }
return ""; 
}

To fix this issue, I rewrote the code using LINQ as follows:

C#
private static string overloadCall<t>(  T source,int param) where T : class
{
    MethodInfo mi = (from a in source.GetType().GetMethods()
                     where a.Name == "myMethod" && a.GetParameters().Length ==
                     param 
                     select a).FirstOrDefault();
    if (param == 1) 
    { 
        object[] arguments = { 1 };
        return mi.Invoke(source, arguments).ToString();
    }
    if (param == 2) 
    {
        object[] arguments = { 1, "abz" };
        return mi.Invoke(source, arguments).ToString(); 
    }

    return "";          
}

This works fine as expected and can be loaded dynamically.

I created the following sample program to check all the above mentioned implementations:

C#
static class Program
{
static void Main(string[] args)
{
    person P = new person();
    DateTime start = DateTime.Now;
    Console.WriteLine("Start Classic Load: {0}", start);
    System.Console.WriteLine(
        "No of String Member in Classic way without linq Person Object : " +
        P.StringMemeberCount().ToString());
    DateTime stop = DateTime.Now;
    Console.WriteLine("Stop Classic Load: {0}", stop.Date.Millisecond);
    Console.WriteLine("Elapsed Time: {0}", stop - start);
    start = DateTime.Now;
    Console.WriteLine("Start Linq Method : {0}", start);
    System.Console.WriteLine("No of String Member in Person Object : " +
        P.StringMemeberCount().ToString());
    stop = DateTime.Now;
    Console.WriteLine("Stop Linq Method : {0}", stop);
    Console.WriteLine("Elapsed Time: {0}", stop - start);

    System.Console.WriteLine("No of Non-String Member in Person Object : " +
       P.nonStringMemeberCount().ToString());
    ///Calling Over loaded Methods ...
    try
    {
        System.Console.WriteLine("Calling overloaded Method with one parameter : " +
            overloadCallClassic(P, 1));
    }
    catch (Exception e)
    {
        System.Console.WriteLine("Calling overloaded Exception : " + e.Message );
    }

    System.Console.WriteLine("Calling overloaded Method with one parameter : " +
        overloadCall(P,1));
    System.Console.WriteLine("Calling overloaded Method with 2 parameters : " +
        overloadCall(P,2));
     System.Console.ReadKey();
}

When the project is compiled and executed, the result will be:

Image 1

Points of Interest

This will run on Visual Studio 2008 and .NET 3.5.

This is how I relished the power of LINQ to objects to access the Collection object with ease and in an effective way.

This really helped me in reducing my lines of code to a greater extent and gave better performance. :)

Here I have used Extension methods which is another interesting feature of C# 3.0.

History

  • 15th September, 2009: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionCan it support MySql Pin
fangyuan31322-Apr-12 17:28
fangyuan31322-Apr-12 17:28 
Questionfaster LINQ? Pin
Milos Tomic21-Sep-09 20:21
Milos Tomic21-Sep-09 20:21 
AnswerRe: faster LINQ? Pin
Appusamy.subbian21-Sep-09 20:48
Appusamy.subbian21-Sep-09 20:48 
GeneralMy vote of 2 Pin
Melionu15-Sep-09 20:42
Melionu15-Sep-09 20:42 
GeneralRe: My vote of 2 Pin
NeoPunk16-Sep-09 9:38
NeoPunk16-Sep-09 9:38 
GeneralMy vote of 4 Pin
Lee Humphries16-Sep-09 10:55
professionalLee Humphries16-Sep-09 10:55 
Melionu wrote:
nothing special

Correct, plus some of the English is a little off, however it's a well structured short introductory article suitable for beginners that explains things as it goes. In other words a classic CP article.
What articles have you written lately?

I just love Koalas - they go great with Bacon.

GeneralRe: My vote of 4 Pin
Appusamy.subbian16-Sep-09 14:44
Appusamy.subbian16-Sep-09 14:44 
GeneralRe: My vote of 4 Pin
Lee Humphries16-Sep-09 16:18
professionalLee Humphries16-Sep-09 16:18 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.