Link to home
Start Free TrialLog in
Avatar of patd1
patd1Flag for United States of America

asked on

Running a static method dynamically

I have saved my class names and method names in a database table. Based on the case type I pickup a class name, a method name  from the database into respective strings and form an Argument String . How do I run this method dynamically? Please see sample code and suggest.

Thank You.
Normally if it weren't in the database I would run like this:
 ArgumentString = "/CaseNum " + caseNo + " /Ver " + StrVer + " /TemplateID " + TemplateID + " /ReportType " + ReportType;
Name189TFConsole.TF189(ArgumentString);

Open in new window


With the strings coming in strings from the database I have the following code:
ArgumentString = "/CaseNum " + caseNo + " /Ver " + StrVer + " /TemplateID " + TemplateID + " /ReportType " + ReportType;
                string ClassName= "Name189TFConsole";
                string MethodName = "TF189";
//code to run the Method here.

Open in new window


Thank You.
Avatar of Todd Gerbert
Todd Gerbert
Flag of United States of America image

Use Type.GetType to initialize a Type to the appropriate class, and Type.InvokeMember to execute a method.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

class Program
{
	static void Main(string[] args)
	{
		string class1 = "TestClass1", method1 = "TestMethod", class2 = "TestClass2", method2 = "OtherTestMethod";

		Type type1 = Type.GetType(class1);
		type1.InvokeMember(method1, BindingFlags.InvokeMethod, null, type1, new object[] { });

		Type type2 = Type.GetType(class2);
		type2.InvokeMember(method2, BindingFlags.InvokeMethod, null, type2, new object[] { });

		Console.ReadKey();
	}
}

public class TestClass1
{
	public static void TestMethod()
	{
		Console.WriteLine("Hello World");
	}
}

public class TestClass2
{
	public static void OtherTestMethod()
	{
		Console.WriteLine("Other Method");
	}
}

Open in new window

Here is one way to do it.  It might not be the best or most efficient way, but it will work:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main( string[] args )
        {
            string className = "Name189TFConsole";
            string methodName = "TF189";

            Assembly thisAssembly = System.Reflection.Assembly.GetExecutingAssembly();
            Type[] thisTypes = thisAssembly.GetTypes();

            foreach ( Type t in thisTypes )
            {
                if ( string.Equals( t.Name, className, StringComparison.InvariantCultureIgnoreCase ) )
                {
                    MethodInfo[] methods = t.GetMethods();

                    foreach ( MethodInfo m in methods )
                    {
                        if ( string.Equals( m.Name, methodName, StringComparison.InvariantCultureIgnoreCase ) )
                        {
                            m.Invoke( null, null );
                        }
                    }
                }
            }
        }
    }

    public class Name189TFConsole
    {
        public Name189TFConsole() { }

        public static void TF189()
        {
            Console.WriteLine( "TF189" );
        }
    }
}

Open in new window

I suppose Dan7el raises a good point about checking the stuff actually exists. ;)

Type.GetType will get the type for you without needing to enumerate all the types in the assembly, and will ignore case.  This example has a method to retrieve the corresponding MethodInfo from the Type (which is just about the same he has above), and then Invokes that MethodInfo.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

class Program
{
	static void Main(string[] args)
	{
		string class1 = "testclass1", method1 = "testmethod", class2 = "testclass2", method2 = "othertestmethod";


		Type t1 = Type.GetType(class1, false, true);
		if (t1 == null)
			Console.WriteLine("Could not find type {0}.", class1);
		else
		{
			MethodInfo staticMethod = GetStaticMethod(t1, method1);
			if (staticMethod == null)
				Console.WriteLine("Could not find method {0}.", method1);
			else
				staticMethod.Invoke(t1, new object[] { });
		}

		Console.ReadKey();
	}

	static MethodInfo GetStaticMethod(Type t, string MethodName)
	{
		foreach (MethodInfo mi in t.GetMethods())
		{
			if (mi.Name.Equals(MethodName, StringComparison.InvariantCultureIgnoreCase) && mi.Attributes.HasFlag(MethodAttributes.Static))
				return mi;
		}

		return null;
	}
}

public class TestClass1
{
	public static void TestMethod()
	{
		Console.WriteLine("Hello World");
	}
}

public class TestClass2
{
	public static void OtherTestMethod()
	{
		Console.WriteLine("Other Method");
	}
}

Open in new window

Avatar of patd1

ASKER

Thanks for the solution. I tried the one suggested by tgerbert and I get the following compilation error:

'System.Reflection.MethodAttributes' does not contain a definition for 'HasFlag' and no extension method 'HasFlag' accepting a first argument of type 'System.Reflection.MethodAttributes' could be found (are you missing a using directive or an assembly reference?)      

Any help is highly appreciated.

Thanks You
HasFlag isn't available until .Net 4.0, you need to manually check the existence of a flag yourself otherwise.  Bit-wise "AND" the Attributes with MethodAttributes.Whatever - if MethodAttributes.Whatever is set the result will be non-zero.

if (aVariable & SomeEnum.SomeFlag != 0)
  hasFlag = true
else
  hasFlag = false

Open in new window

Avatar of patd1

ASKER

Thanks again.
How do I pass parameters to the method?
And how would the invoke change if the method is not static?

example:
76MapToORU Object76 = new 76MapToORU();
Object76.Run(caseNo, Ver, TemplateID, Status); 

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of Todd Gerbert
Todd Gerbert
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of patd1

ASKER

I am getting this exception on line: Type t = Type.GetType(className, true, true);

base {System.SystemException} = {"Could not load type '76CGMapToORU ' from assembly 'Result_Generator_1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.":"76CGMapToORU "}

My current code:
 string className = "76CGMapToORU ";
 string methodName = "Run";
 Type t = Type.GetType(className, true, true); //I hv set throw on error to true to see the exception
....

Open in new window


If I run the code below, it runs fine.
 76CGMapToORU 76CGMapToORUObject = new 76CGMapToORU ();
 76CGMapToORUObject .Run(caseNo, Ver, TemplateID, ReportType);

Open in new window


Thanks for your help.
Avatar of patd1

ASKER

please read as: string className = "76CGMapToORU";
There is no extra space there in the code, but I still get the exception.
Avatar of patd1

ASKER

You can ignore the above messages. I appended the class name with namespace name and that worked.

Thanks for all your help.
Type.GetType() assumes the current assembly.  If 76CGMapToORU appears in a separate assembly, will need to supply a fully-qualified type name (e.g. ClassLibrary1.Class1, ClassLibrary1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null, or get a reference to that assembly and use Assembly.GetType().