A simple apply() implementation using generics

Published Tue, Oct 19 2004 5:04 | girishb

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);

}

}

}