Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

Running a static method dynamically

Posted on 2011-03-22
11
Medium Priority
?
401 Views
Last Modified: 2012-08-14
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.
0
Comment
Question by:patd1
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 5
11 Comments
 
LVL 33

Expert Comment

by:Todd Gerbert
ID: 35192486
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

0
 
LVL 20

Expert Comment

by:Daniel Van Der Werken
ID: 35192535
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

0
 
LVL 33

Expert Comment

by:Todd Gerbert
ID: 35192673
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

0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 

Author Comment

by:patd1
ID: 35300417
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
0
 
LVL 33

Expert Comment

by:Todd Gerbert
ID: 35300440
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

0
 

Author Comment

by:patd1
ID: 35301254
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

0
 
LVL 33

Accepted Solution

by:
Todd Gerbert earned 2000 total points
ID: 35304661
Passing parameters is done by passing an array object[] in the call t Invoke. In the snippet I posted above (http:#a35192673) on line 23 the call to Invoke has an empty object[] array because the method doesn't take parameters, if it did take a string and an int as parameters that line would have looked like:
staticMethod.Invoke(t1, new object[] { "Hello World", 33 });

Open in new window


A method that is not static is an instance method, and requires that a specific instance of a class (i.e. an object) be created before you can call it. For example, you can't write:
object littleLetters = String.ToLower();

Open in new window

Because it's senseless to say lower-case the string, without saying which string to lower-case. You need to create an instance of a string, then you can call .ToLower() on that instance:
string message = "HeLlO wOrLd";
object littleLetters = message.ToLower();

Open in new window


So, when you're doing it dynamically at run-time you can use Assembly.CreateInstance to create a specific instance of a class by specifying it's name as a string. http://msdn.microsoft.com/en-us/library/system.reflection.assembly.createinstance(v=VS.90).aspx

You can run this code below, and when prompted enter "TestClass" for a class name, and "Add" for a method name.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

class Program
{
	static void Main(string[] args)
	{
		Console.Write("Enter a class name to create instances of: ");
		string className = Console.ReadLine();

		Console.Write("Enter a method of the class to invoke: ");
		string methodName = Console.ReadLine();

		Type t = Type.GetType(className, false, true); // Get a Type representing the class we want to create an instance of

		if (t == null)
			Console.WriteLine("Could not find the class {0}.", className);
		else
		{
			// Create the instances of TestClass
			// The following CreateInstance call is equivelant to: object obj1 = new TestClass(10);
			object obj1 = t.Assembly.CreateInstance(
				className,					// Name of class to create instance of
				true,						// True to ignore case
				BindingFlags.CreateInstance,// Tell Reflection we're creating an instance of a class
				null,						// Use the default binder
				new object[] { 10 },		// Pass arguments to the constructor, in this case a single int
				null,						// Use current thread's culture info
				new object[] { });			// No activation attributes, so pass empty object[] array

			// This CreateInstance is equal to: object obj2 = new TestClass(50);
			object obj2 = t.Assembly.CreateInstance(className, true, BindingFlags.CreateInstance, null,
				new object[] { 50 }, null, new object[] { });

			if (obj1 == null || obj2 == null)
				Console.WriteLine("Could not create an instance of {0}.", className);
			else
			{
				MethodInfo method = GetPublicInstanceMethod(t, methodName);
				if (method == null)
					Console.WriteLine("Couldn't find the method {0} in the class {1}.", methodName, className);
				else
				{
					// Invoke the method - specify WHICH object to invoke the method on
					// in the first parameter to Invoke, and pass the parameters of the
					// method we're invoking as an array[] of objects
					object result1 = method.Invoke(obj1, new object[] { 5 });
					object result2 = method.Invoke(obj2, new object[] { 75 });

					Console.WriteLine("The {0} method of obj1 returned {1}.", methodName, result1);
					Console.WriteLine("The {0} method of obj2 returned {1}.", methodName, result2);

					// Get another test method with some more parameters
					MethodInfo m = GetPublicInstanceMethod(t, "GetMessage");
					// Pass all the parameters for the GetMessage method
					// in the object[] array
					object result3 = m.Invoke(obj1, new object[] { DateTime.Now, "Hello", "World", 17 });
					Console.WriteLine("Third result: {0}", result3);
				}
			}
		}

		Console.WriteLine("Press any key to exit.");
		Console.ReadKey();
	}

	static MethodInfo GetPublicInstanceMethod(Type t, string MethodName)
	{
		MethodName = MethodName.ToLower();
		foreach (MethodInfo mi in t.GetMethods())
		{
			// We're looking for a method with the specified name that is public, and is NOT static
			if (mi.Name.ToLower() == MethodName && HasMethodAttribute(mi, MethodAttributes.Public) && !HasMethodAttribute(mi, MethodAttributes.Static))
				return mi;
		}
		return null;
	}

	static bool HasMethodAttribute(MethodInfo method, MethodAttributes attribute)
	{
		return (method.Attributes & attribute) != 0;
	}
}

public class TestClass
{
	private int _value;
	public TestClass(int Value)
	{
		_value = Value;
	}
	public int Add(int ValueToAdd)
	{
		return _value + ValueToAdd;
	}
	public string GetMessage(DateTime dt, string part1, string part2, int n)
	{
		return String.Format("{0} {1} {2}, number: {3}",
			dt, part1, part2, n);
	}
}

Open in new window

0
 

Author Comment

by:patd1
ID: 35315935
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.
0
 

Author Comment

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

Author Comment

by:patd1
ID: 35316167
You can ignore the above messages. I appended the class name with namespace name and that worked.

Thanks for all your help.
0
 
LVL 33

Expert Comment

by:Todd Gerbert
ID: 35316171
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().
0

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Article by: Najam
Having new technologies does not mean they will completely replace old components.  Recently I had to create WCF that will be called by VB6 component.  Here I will describe what steps one should follow while doing so, please feel free to post any qu…
Exception Handling is in the core of any application that is able to dignify its name. In this article, I'll guide you through the process of writing a DRY (Don't Repeat Yourself) Exception Handling mechanism, using Aspect Oriented Programming.
Video by: ITPro.TV
In this episode Don builds upon the troubleshooting techniques by demonstrating how to properly monitor a vSphere deployment to detect problems before they occur. He begins the show using tools found within the vSphere suite as ends the show demonst…
In this video you will find out how to export Office 365 mailboxes using the built in eDiscovery tool. Bear in mind that although this method might be useful in some cases, using PST files as Office 365 backup is troublesome in a long run (more on t…

705 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question