I'm writing a utility program. In fact, the program will be a Console application that will contain many static methods, each method being a specific utility.

The application will take two command line arguments: filename, and utility name. Of course I want to run the method specified on the file specified.

I want to discuss approaches to this. Each method may have a unique signature and return value/type.

Thinking through this, I need a way to

1) check to see if the method on the commandline exists in the program. I could create an array of all method names, and check against the array. Simple enough, but is there a more elegant way? Does a class contain knowledge of its own members?

2) invoke any particular method, given a string. That string would be the method name.

How would I know what parameters I need to pass to the method? They wouldn't come from the commandline. I need some way of knowing, gathering, and passing in all required parameters/objects.

What I'm thinking is that the Main() method will declare a FileStream, plus any other objects that may be needed by any of the utility methods. I need some way to "map" these objects to the parameters needed by the method I want to call.

Again, I could create some data structure that said "if arg[1] equals this string, then call this method with these parameters". The problem is that becomes more to maintain. When a new utility is added to the program, I'll have to write the utility method, PLUS define any new objects the utility may need in Main(), PLUS update the structure that maps arg[1] to the new method. I'm looking for clever ways to avoid that final step.

I'm looking for other ideas, pointers to articles, general discussion, anything that would help me to think through this project.

It looks like the System.Reflection class has everything I might need. As this develops, I'll post code. I'd still like any input anyone has to offer.

Why does it always seem that when I post C# threads, I'm only talking to myself? In any case, I've hit my first snag. I've reached the point where I want to invoke a public, static method that's defined in the current class. All the System.Reflection examples I've found are for invoking methods from a different class, or an assembly, or on instance objects. How do you invoke a STATIC (ie, "class method") method of the CURRENT class?

Code:

using System;
using System.IO;
using System.Collections;
using System.Reflection;

namespace pcl_util
{
	/// <summary>
	/// Summary description for Class1.
	/// </summary>
	class Class1
	{
		static string filename;
		static string function;
		static FileStream baseFS;


		[STAThread]
		static void Main(string[] args)
		{
			// get filename to process, if found, declare a FileStream
			filename = args[0].ToString();
			if (File.Exists(filename))
			{
				baseFS = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read, 8192);
			}
			else
			{
				Console.WriteLine("FILE NOT FOUND: " + filename);
			}

			// does function exist in this program? If so, get its parameters and run it
			function = args[1].ToString();
			if (checkFunction(function))
			{
				Type myType = typeof(Class1);
				MethodInfo myMethodInfo = myType.GetMethod(function);
				ParameterInfo[] myParameters = myMethodInfo.GetParameters();
				
				// collect parameters, call method.
				object[] methodParams = new Object [myParameters.Length];
				int mpIndex = 0;
				foreach( ParameterInfo paramInfo in myParameters)
				{
					if (paramInfo.ParameterType == Type.GetType("System.IO.FileStream"))
					{
						methodParams[mpIndex] = baseFS;
					}

					mpIndex++;
				}

				myType.InvokeMember(function,
					BindingFlags.DeclaredOnly |
					BindingFlags.Public |
					BindingFlags.InvokeMethod, null, null, methodParams);

			}
			else
			{
				Console.WriteLine("FUNCTION NOT FOUND: " + function);
			}
	}

		public static bool checkFunction(string f)
		{
			Type myType = typeof(Class1);
			MethodInfo myMethodInfo = myType.GetMethod(f);

			if (myMethodInfo == null)
			{
				return false;
			}
			else
			{
				return true;
			}
		}

		public static System.Int32 getFF(FileStream fs)
		{
			// get the byte position of all FF in file
			Console.WriteLine("getFF ran.");

			return 0;
		}
	}
}

The problem is in the InvokeMethod() method. The second "null" in the parameter list is supposed to be an object. What object? The only object is the currently running instance of the current class. I'm confused.

For the command line arguments, I'm passing in a valid filename, and the string "getFF". The above code is supposed to invoke the getFF() method.

On the other hand, this code works fine:

Type myType = typeof(Class1);
				MethodInfo myMethodInfo = myType.GetMethod(function);
				ParameterInfo[] myParameters = myMethodInfo.GetParameters();
				
				// collect parameters, call method.
				object[] methodParams = new Object [myParameters.Length];
				int mpIndex = 0;
				foreach( ParameterInfo paramInfo in myParameters)
				{
					if (paramInfo.ParameterType == Type.GetType("System.IO.FileStream"))
					{
						methodParams[mpIndex] = baseFS;
					}

					mpIndex++;
				}

				object retval = myType.GetMethod(function).Invoke(null, methodParams);

The question is, "why?". The invoke method calls for two parameters, object, and the method parameters, as an object array.

I've passed in "null" as the object, because there is NOT an instance object. All methods are static. The only instance is the currently running program. Is "null" correct, then, or is there a proper way to refer to the currently running program?

Another little snag: how does one dynamically declare an object to be of a certain type?

In other words, MethodInfo.ReturnType tells you the defined return type of the method. So how do you declare a return object/variable of that type?

how does one dynamically declare an object to be of a certain type?

Do you mean generics? I.e say you wanted to create a stack but you didn't know if it was a going to be a stack of integer/strings? I guess you would use generics?

This article has been dead for over six months. Start a new discussion instead.