Using LINQ with System.Reflection Classes
C# 3.0 and LINQ is not only about accessing data in relational databases and LINQ queries can be used against in-memory data structures as well. Yesterday I had to discover all methods in an assembly satisfying some criteria. As I as playing with Visual Studio 2008 Beta 2 I tried to use new language features everywhere (well, even where it was unnecessary).
I used Linq to filter my classes and methods and wrote this code in a functional style as I am not familiar with LINQ query syntax in C# 3.0.
public IEnumerable<Action> LocateActions(){
return GetType().Assembly.GetTypes()
.Where(v => v.GetCustomAttributes(
typeof(ActionContainerAttribute), true).Length > 0)
.SelectMany(v => v.GetMethods(BindingFlags.Public |
BindingFlags.Instance))
.Where(v => v.GetCustomAttributes(
typeof(ActionAttribute), true).Length > 0)
.Select(v => new Action(v));
}
My first version works fine for me; I created the second and third versions just to see what is the most readable. So, the second version of the same method is C# 2.0:
public IEnumerable<Action> LocateActions2(){
foreach (Type t in GetType().Assembly.GetTypes())
{
if (t.GetCustomAttributes(
typeof(ActionContainerAttribute), true).Length > 0)
{
foreach (MethodInfo mi in t.GetMethods(BindingFlags.Public |
BindingFlags.Instance))
{
if (mi.GetCustomAttributes(typeof(ActionAttribute),
true).Length > 0)
{
yield return new Action(mi);
}
}
}
}
}
and I got the last one from C# 2.0 code.
public IEnumerable<Action> LocateActions3(){
return
from t in GetType().Assembly.GetTypes()
where
t.GetCustomAttributes(typeof(ActionContainerAttribute),true).Length> 0
from mi in t.GetMethods(BindingFlags.Public | BindingFlags.Instance)
where
mi.GetCustomAttributes(typeof(ActionAttribute), true).Length > 0
select
new Action(mi);
}
}
The first one remains for me the most clear and easy to read, but I believe that not everyone will agree with me.
Which one is the easiest to read for you?