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:
- Dynamically getting the count of Property of specific Type in an object
- 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:
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.
private static int StringMemeberCountClassic<T>(this T source) where T : class
{
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
.
private static int StringMemeberCount<t>(this T source) where T : class
{
int iret = (from a in source.GetType().GetProperties()
where a.PropertyType.Name == "String"
select a).Count();
return iret;
}
private static int nonStringMemeberCount<t>(this T source) where T : class
{
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:
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:
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:
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());
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:
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
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.