my application is currently reading in a list of methods that I need to invoke, from the Database, and putting them into strings.
I want to be able to invoke these methods by their name, and pass parameters to them.
Heres a simple example of what I want to achieve:
protected void Page_Load(object sender, EventArgs e)
{
...
...
string MethodOne = "CombineText";
string WordOne = "Hello";
string WordTwo = "World";
CombineText(WordOne, WordTwo);
}
public void CombineText(string WordOne, string WordTwo)
{
Console.WriteLine(WordOne+" "+WordTwo);
}
I've seen plenty of examples online about invoking static methods, but I can't figure out how to invoke Public Void methods by name from strings.
Does anybody have any ideas? Much Appreciated!
You can use reflection.
MethodInfo mi = this.GetType().GetMethod(MethodOne);
mi.Invoke(this, new object[] { WordOne, WordTwo };
I would recommend using a switch instead of trying to call the method based on it's name.
switch(MethodOne)
{
case "CombineText":
CombineText(WordOne, WordTwo);
break;
default:
Console.WriteLine("Invalid function: " + MethodOne);
break;
}
This has the advantage of ensuring that you only accept valid arguments, and provides a way to sanitize the inputs on a per-function basis before evaluating (maybe you want to strip spaces from WordTwo for one function, for instance, or you want to pass the longer one in as the first parameter regardless of order.).
Assuming the method is an instance method of the current type:
MethodInfo method = this.GetType().GetMethod(MethodOne);
method.Invoke(this, new[] { WordOne, WordTwo });
You need to look at reflection. You need to do something like this:
Type type = GetType();
MethodInfo method = type.GetMethod(Method);
Method.Invoke(this, new object[] { WordOne, WordTwo });
http://msdn.microsoft.com/en-us/library/8zz808e6.aspx
http://msdn.microsoft.com/en-us/library/a89hcwhh.aspx
Related
I try to set a method as a parameter but I can't do it.
I tried about ten solutions proposed on different topics but it didn't work that's why I create my own topic
public static void startThread(Method methodname (For exemple Class.test))
{
for (int i = 1; i <= Xenoris.threads; i++)
{
new Thread(new ThreadStart(methodname)).Start();
}
}
As you can see I try to do ThreadStart in a function but for that I need to have a method as a parameter which I can't do
To be more precise I want to make my own library and I need to be able to have methods as parameter like: Class.test
I hope someone can help me and I'm sorry for my bad English
In this case, ThreadStart itself is a delegate, so you could just use that as the parameter type:
public static void startThread(ThreadStart method)
{
for (int i = 1; i <= Xenoris.threads; i++)
{
new Thread(method).Start();
}
}
And you can directly pass in the name of the method without any parentheses:
startThread(SomeMethod);
Note that the method you pass must be a method that accepts no parameters and returns void.
I have been workig on a report on delegates for some time now in addition to working with them for over a year.
Looking up some info on the differences between anonymous methods used in C# 2.0 and lambda expressions in C# i read something about a functionality that 2.0 anonymous methods provide which lambda's dont: they can omit the parameter list.
After doing some research on this i try testing this out on my personal IDE which is running the latest version of C#, finding out that when i try to assign an anonymous method without any parameters to my Delegate type using them i get an error:
Delegate Test.MyHelloDelegate does not take 0 arguments
class TestClass
{
public delegate void MyHelloDelegate (string s);
MyHelloDelegate Hello = delegate () { Console.WriteLine("Hello from delegate"); };
private void CallHello ()
{
Hello("dummy");
}
}
My own assumption would be that it got patched out since people will only use lambda's anyway but i do need some evidence for that since i will be putting it in my report. Would love to know if someone has any idea what is going on with this.
Yes, cause your attached anonymous method doesn't takes an input parameter. Change it to
public delegate void MyHelloDelegate (string s);
MyHelloDelegate Hello = delegate(string s) { Console.WriteLine("Hello from delegate " + s); };
If you don't want pass any parameter then consider using the syntax below
MyHelloDelegate Hello = delegate { Console.WriteLine("Hello from delegate "); };
I have a string whose content is name of 1 function in my WP apps. For example, assume that I have:
string functionName = "button3_Click"
So I would like to call the button3_Click() in my apps. I tried the GetRuntimeMethod method in System.Reflection but the result returned is null, so when I use invoke I got the System.NullReferenceException. My code to call this function is:
System.Type[] types = { typeof(MainPage), typeof(RoutedEventArgs) };
string functionName = "button3_Click";
System.Type thisType = this.GetType();
MethodInfo method = thisType.GetRuntimeMethod(functionName, types);
object[] parameters = {this, null};
method.Invoke(this, parameters);
And the prototype of button3_Click is:
private void button3_Click(object sender, RoutedEventArgs e)
So how can I call the function whose name contained in the string? Thank you so much for you help.
Update
I can call the button3_Click() method by changing access level of this method to public, is there any way to keep access level of this method is private and I can call this method? Thank you for your help.
Finally
I think I should use the code like this, it can get all method even its access level is private or public:
System.Type[] types = { typeof(MainPage), typeof(RoutedEventArgs) };
string functionName = "button6_Click";
TypeInfo typeinfo = typeof(MainPage).GetTypeInfo();
MethodInfo methodinfo = typeinfo.GetDeclaredMethod(functionName);
object[] parameters = {this, null};
methodinfo.Invoke(this, parameters);
Thank you for your help.
If your app is a Windows Runtime app, use GetTypeInfo extension method on thisType and then use TypeInfo.GetDeclaredMethod method:
using System.Reflection;
...
System.Type thisType = this.GetType();
TypeInfo thisTypeInfo = thisType.GetTypeInfo();
MethodInfo method = thisTypeInfo.GetDeclaredMethod(functionName);
object[] parameters = {this, null};
method.Invoke(this, parameters);
It is said in documentation that GetDeclaredMethod returns all public members of a type, but according to .NET Reference Source, the documentation seems to be incorrect: it calls Type.GetMethod with flags constant that contains BindingFlags.NonPublic.
There are restrictions on Silverlight reflection:
In Silverlight, you cannot use reflection to access private types and members. If the access level of a type or member would prevent you from accessing it in statically compiled code, you cannot access it dynamically by using reflection. (source)
Look into LambdaExpressions as it might be a workaround in this case.
I'm trying to code what I've called a 'trigger'. They take an object, a function and some kind of activation criteria. Once activated, it runs the method on that object.
Here's a basic stripped down example. It works as expected for now. An example usage would be:
SomeObject myObj = new SomeObject();
MyTrigger trigger = new MyTrigger(myObj, "Delete");
trigger.Activate(); // calls myObj.Delete();
Now where I've called Invoke with null is where parameters can normally go (I think). The problem I'm having is getting the 'zero or more paramters' as a single parameter in the function declaration. I need a thrid parameter when creating MyTrigger that would be the parameters to pass during the Invoke.
Or is there an even better way to do it? I.e. Can I somehow pass the object, the function call and the parameters as a single parameter? Maybe two parameters?
You have to use delegates.
// rewrite your trigger constructor like this
class MyTrigger<TTarget>
{
public MyTrigger(TTarget target, Action<TTarget> action);
public void Activate()
{
this._action(this._target);
}
}
// now call it with or without parameters
SomeObject myObj = new SomeObject();
var trigger = new MyTrigger<SomeObject>(myObj, o => o.Delete(1234));
trigger.Activate();
You can also create a static helper class to make the creation code slightly simpler to write:
static class MyTrigger
{
public MyTrigger<TTarget> Create<TTarget>(TTarget target, Action<TTarget> action)
{
return new MyTrigger<TTarget>(target, action);
}
}
// now write the initialization code like this (you don't have to specify the type parameter anymore):
var trigger = MyTrigger.Create(myObj, o => o.Delete());
You could use the params keyword:
public Trigger(object targetObject, string methodName, params object[] parameters)
{
//"parameters" here will be an array of length 0 if no parameters were passed
}
MyTrigger trigger = new MyTrigger(myObj, "Delete"); //no parameters
MyTrigger trigger = new MyTrigger(myObj, "Delete", param1); //one parameter
MyTrigger trigger = new MyTrigger(myObj, "Delete", param1, param2); //two parameters
But I prefer Knagis' answer because it will also provide you compile-time safety (and likely the Trigger class will be far simplified and ditch any reflection that you probably have in there.)
Is there any way in C# to pass a random method as a parameter?
To explain my question:
I want to write a simple Logger-Tool that reports the entering and leaving of a method with the passed arguments an the class and method name:
The log file I'm aiming at:
ENTERING: ClassOfDoom::MethodOfDoom( arg1={1} [int], arg2={true} [bool] )
LEAVING: ClassOfDoom::MethodOfDoom RETURNING 1 [int]
The code I have in mind:
class ClassOfDoom {
// Remeber: MethodOfDoom is a _random_ method with _random_ arguments
public int MethodOfDoom(int arg1, bool arg2) {
Log.Entering(this, this.MethodOfDoom, arg1, arg2);
...
return Log.Returing(this, this.MethodOfDoom, 1);
}
}
Is there a way to achieve this? Or isn't C# as flexible as that?
Thanks in advance!
You can make your logging function take a MethodBase argument and use MethodBase.GetCurrentMethod to pass the current method info as an argument.
Then, in the logger, you could check its properties Name and DeclaringType to get the method information. Also, passing parameters is easy by declaring a params object[] args parameter in the logging function:
public static void Entering(object obj, MethodBase methodInfo,
params object[] args) {
Console.WriteLine("ENTERING {0}:{1}", methodInfo.DeclaringType.Name,
methodInfo.Name);
...
}
I'm not sure I entirely understand your question, but if you are trying to make a call to Log.Entering and Log.Returning inside an arbitrary (random) method and using the method's actual parameters, you should check out PostSharp. It will allow you to inject code in a method body and then do some work based on the reflected method information you get from the .NET framework (and the actual parameters passed to the method at runtime).
You could do it with Expression easily enough - it would look something like:
Log.Capture(() => this.MethodOfDoom(arg1, arg2));
Here's an example; I've been a bit lazy using Compile().DynamicInvoke() to read the arg-values - for real code I'd try to read it more directly:
using System;
using System.Diagnostics;
using System.Linq.Expressions;
class Program
{
DateTime MethodOfDoom(string s, int i)
{
return DateTime.Today;
}
public void RunTest()
{
int i =123;
Log.Capture(() => this.MethodOfDoom("abc", i));
}
static void Main()
{
new Program().RunTest();
}
}
static class Log
{
public static T Capture<T>(Expression<Func<T>> method)
{
MethodCallExpression mce = method.Body as MethodCallExpression;
if (mce == null) throw new InvalidOperationException(
"Method-call expected");
string name = mce.Method.Name;
try
{
int i = 0;
foreach(var param in mce.Method.GetParameters())
{
object argValue = Expression.Lambda(mce.Arguments[i++])
.Compile().DynamicInvoke();
Trace.WriteLine(param.Name + "=" + argValue, name);
}
Trace.WriteLine("ENTERING", name);
T result = method.Compile().Invoke();
Trace.WriteLine("EXITING: " + result, name);
return result;
}
catch (Exception ex)
{
Trace.WriteLine("EXCEPTION: " + ex, name);
throw;
}
}
}
If widely used in your code, this scenario is best implemented using Aspect Oriented Programming (AOP) techniques. There are different frameworks that can be used (such as Spring.NET AOP), which you can use in your .NET application. Here is a reference article that might help you get started:
http://www.developer.com/lang/article.php/10924_3795031_2
The referenced article gives you the logging enter/exit scenario as an example.
I have used PostSharp to do this very thing before.