You know how you start off in one place thinking you will do
something and end up doing something entirely different because you are flying
coding..
Well, that is what happened to me here. I was thinking of
trying to figure out a way to get a way of applying some method on a set of
data elements within a sequence. I was hoping that I could use DynamicMethod
in doing so. Well, After I worked on it a bit and it turned out that I don’t
need DynamicMethod
for what I was trying to do. I could do it just with Reflection and bit of
Generics magic.
This whole thing came about because of Bruce Eckel’s excellent article here.
public
static
void
apply<S, U, T>(S s, String
methodName)
and its various incarnations are basically a way of
iterating on a sequence (S) with a type (U) while calling methodName within an
object (T). Current (naïve) implementation just re-creates T every
iteration. One of the improvements can be to have one object created and use
that in the loop which allows us to do some of the accumulative operations. The
other improvement that I would like to do is to take MethodInfo as input to the
call (so that you can pass in delegates to be invoked).
The heart of the operations is of course, GetMethodFor, is a
reflection based operation. That means you will see runtime exceptions instead
of compile time failures when passed the wrong types. You can probably avoid
that a little by using the overloads that take the argument types as arguments
for the generic. E.g. public
static
void
apply<S, U, T, A1, A2>(S s, String
methodName, A1 a1, A2 a2).
It might be feasible to implement this better. I am
confident that this would be slower than writing a direct call to the method
hardwiring the input args.
#region Using directives
using System;
using
System.Collections.Generic;
using
System.Text;
using
System.Reflection;
#endregion
namespace DynaMet
{
class ApplyDynamic
{
private static MethodInfo
GetMethodFor<T,U>(String
s, params
object[]
args)
{
int len = args
!= null
? args.Length : 0;
Type[] tArr = new Type[len + 1];
tArr[0] = typeof(U);
int i = 1;
if (args != null)
{
foreach (object o in args)
{
tArr[i++]
= o.GetType();
}
}
MethodInfo m = typeof(T).GetMethod(s,
tArr);
return m;
}
public static void
apply<S, U, T>(S s, String
methodName)
where S : IEnumerable<U>
where T : new()
{
MethodInfo m =
GetMethodFor<T,U>(methodName,null);
foreach (U o in s)
{
m.Invoke(new T(), new object[] { o });
}
}
public static void
apply<S, U, T, A1>(S s, String
methodName, A1 a)
where S : IEnumerable<U>
where T : new()
{
MethodInfo m =
GetMethodFor<T, U>(methodName, new object[] { a });
foreach (U o in s)
{
object[] args = new object[] { o, a
};
m.Invoke(new T(),
args);
}
}
public static void
apply<S, U, T, A1, A2>(S s, String
methodName, A1 a1, A2 a2)
where S : IEnumerable<U>
where T : new()
{
MethodInfo m =
GetMethodFor<T, U>(methodName, new object[] { a1,
a2 });
foreach (Object o in s)
{
object[] args = new object[] { o,
a1, a2 };
m.Invoke(new T(),
args);
}
}
public static void
apply<S, U, T>(S s, String
methodName, params
object[]
args) where
S : IEnumerable<U>
where
T:new()
{
MethodInfo m =
GetMethodFor<T, U>(methodName, args);
foreach (U o in s)
{
object[] args2 =
new
object[args.Length
+ 1];
args2[0]
= o;
Array.Copy(args,
0, args2, 1, args.Length);
m.Invoke(new T(),
args2);
}
}
}
class Dynamic
{
public virtual void Print()
{
Console.WriteLine("No
arguments");
}
public void Print(string printMe)
{
Console.WriteLine("One
Argument :{0}",
printMe);
}
public void Print(string printMe, int
printThisToo)
{
Console.WriteLine("Two
Argument: {0},{1}",
printMe,printThisToo);
}
private int t;
public void Do()
{
t++;
}
static void Main(string[]
args)
{
List<String> arr =
new
List<String>();
for (int i = 0; i
< 5; i++) arr.Add(i.ToString());
ApplyDynamic.apply<List<String>, String, Dynamic>(arr, "Print",12);
}
}
}