I'm developing a simulation game where I have some conditional methods in various classes which I want to use them for random in-game events.
My aim is creating a user-friendly event class where users can add events via XML serializing (that part is good to go). So I'm trying to keep things simple and generic as much as possible. I got some conditional methods in various classes like
public class Person
{
static bool IsOlderThan(int age) {/*...*/}
}
public class Faction
{
static bool HasRelationMoreThan(Faction faction,float value) {/*...*/}
}
and so on...
I must define a Func<> parameter or another delegate which can accept these methods with different scope of parameters, instead of defining a different field for every single one of them. TL;DR: I need a delegate type which accepts any method as value.
Is there any way to create a flexible, generic method reference like this?
Take a look at the MulticastDelegate class. It's a base class for all delegates.
But be careful. MulticastDelegates are invoked via DynamicInvoke(), which works slower than Invoke(). And you also have to control number and types of parameters passed into DynamicInvoke() because it can cause runtime errors.
private void TestMulticastDelegate()
{
Func<int, bool> function1 = IntToBool;
Func<string, bool> function2 = StringToBool;
Func<int, string, bool> function3 = IntAndStringToBool;
int intArg = 1;
string stringArg = "someString";
MulticastDelegate d;
d = new Func<int, bool>(IntToBool);
bool res1 = d.DynamicInvoke(intArg).Equals(function1(intArg)); // always true
d = new Func<string, bool>(StringToBool);
bool res2 = d.DynamicInvoke(stringArg).Equals(function2(stringArg)); // always true
d = new Func<int, string, bool>(IntAndStringToBool);
bool res3 = d.DynamicInvoke(intArg, stringArg).Equals(function3(intArg, stringArg)); // always true
}
private bool IntToBool(int i)
{
return i == 0;
}
private bool StringToBool(string s)
{
return string.IsNullOrEmpty(s);
}
private bool IntAndStringToBool(int i, string s)
{
return i.ToString().Equals(s, StringComparison.OrdinalIgnoreCase);
}
Related
I have several methods all with the same parameter types and return values but different names and blocks. I want to pass the name of the method to run to another method that will invoke the passed method.
public int Method1(string)
{
// Do something
return myInt;
}
public int Method2(string)
{
// Do something different
return myInt;
}
public bool RunTheMethod([Method Name passed in here] myMethodName)
{
// Do stuff
int i = myMethodName("My String");
// Do more stuff
return true;
}
public bool Test()
{
return RunTheMethod(Method1);
}
This code does not work but this is what I am trying to do. What I don't understand is how to write the RunTheMethod code since I need to define the parameter.
You can use the Func delegate in .NET 3.5 as the parameter in your RunTheMethod method. The Func delegate allows you to specify a method that takes a number of parameters of a specific type and returns a single argument of a specific type. Here is an example that should work:
public class Class1
{
public int Method1(string input)
{
//... do something
return 0;
}
public int Method2(string input)
{
//... do something different
return 1;
}
public bool RunTheMethod(Func<string, int> myMethodName)
{
//... do stuff
int i = myMethodName("My String");
//... do more stuff
return true;
}
public bool Test()
{
return RunTheMethod(Method1);
}
}
You need to use a delegate. In this case all your methods take a string parameter and return an int - this is most simply represented by the Func<string, int> delegate1. So your code can become correct with as simple a change as this:
public bool RunTheMethod(Func<string, int> myMethodName)
{
// ... do stuff
int i = myMethodName("My String");
// ... do more stuff
return true;
}
Delegates have a lot more power than this, admittedly. For example, with C# you can create a delegate from a lambda expression, so you could invoke your method this way:
RunTheMethod(x => x.Length);
That will create an anonymous function like this:
// The <> in the name make it "unspeakable" - you can't refer to this method directly
// in your own code.
private static int <>_HiddenMethod_<>(string x)
{
return x.Length;
}
and then pass that delegate to the RunTheMethod method.
You can use delegates for event subscriptions, asynchronous execution, callbacks - all kinds of things. It's well worth reading up on them, particularly if you want to use LINQ. I have an article which is mostly about the differences between delegates and events, but you may find it useful anyway.
1 This is just based on the generic Func<T, TResult> delegate type in the framework; you could easily declare your own:
public delegate int MyDelegateType(string value)
and then make the parameter be of type MyDelegateType instead.
From OP's example:
public static int Method1(string mystring)
{
return 1;
}
public static int Method2(string mystring)
{
return 2;
}
You can try Action Delegate! And then call your method using
public bool RunTheMethod(Action myMethodName)
{
myMethodName(); // note: the return value got discarded
return true;
}
RunTheMethod(() => Method1("MyString1"));
Or
public static object InvokeMethod(Delegate method, params object[] args)
{
return method.DynamicInvoke(args);
}
Then simply call method
Console.WriteLine(InvokeMethod(new Func<string,int>(Method1), "MyString1"));
Console.WriteLine(InvokeMethod(new Func<string, int>(Method2), "MyString2"));
In order to provide a clear and complete answer, I'm going to start from the very beginning before showing three possible solutions.
A brief introduction
All .NET languages (such as C#, F#, and Visual Basic) run on top of the Common Language Runtime (CLR), which is a VM that runs code in the Common Intermediate Language (CIL), which is way higher level than machine code. It follows that methods aren't Assembly subroutines, nor are they values, unlike functional languages and JavaScript; rather, they're symbols that CLR recognizes. Not being values, they cannot be passed as a parameter. That's why there's a special tool in .NET. That is, delegates.
What's a delegate?
A delegate represents a handle to a method (the term handle is to be preferred over pointer as the latter would be an implementation detail). Since a method is not a value, there has to be a special class in .NET, namely Delegate, which wraps up any method. What makes it special is that, like very few classes, it needs to be implemented by the CLR itself and couldn't be simply written as a class in a .NET language.
Three different solutions, the same underlying concept
The type–unsafe way
Using the Delegate special class directly.
Example:
static void MyMethod()
{
Console.WriteLine("I was called by the Delegate special class!");
}
static void CallAnyMethod(Delegate yourMethod)
{
yourMethod.DynamicInvoke(new object[] { /*Array of arguments to pass*/ });
}
static void Main()
{
CallAnyMethod(MyMethod);
}
The drawback here is your code being type–unsafe, allowing arguments to be passed dynamically, with no constraints.
The custom way
Besides the Delegate special class, the concept of delegates spreads to custom delegates, which are declarations of methods preceded by the delegate keyword. They are type–checked the same way as “normal” method invocations, making for type-safe code.
Example:
delegate void PrintDelegate(string prompt);
static void PrintSomewhere(PrintDelegate print, string prompt)
{
print(prompt);
}
static void PrintOnConsole(string prompt)
{
Console.WriteLine(prompt);
}
static void PrintOnScreen(string prompt)
{
MessageBox.Show(prompt);
}
static void Main()
{
PrintSomewhere(PrintOnConsole, "Press a key to get a message");
Console.Read();
PrintSomewhere(PrintOnScreen, "Hello world");
}
The standard library's way
Alternatively, you can stick with a delegate that's part of the .NET Standard:
Action wraps up a parameterless void method;
Action<T1> wraps up a void method with one parameter of type T1;
Action<T1, T2> wraps up a void method with two parameters of types T1 and T2, respectively,
and so forth;
Func<TR> wraps up a parameterless function with TR return type;
Func<T1, TR> wraps up a function with TR return type and with one parameter of type T1;
Func<T1, T2, TR> wraps up a function with TR return type and with two parameters of types T1 and T2, respectively;
and so forth.
However, bear in mind that by using predefined delegates like these, parameter names won't be self-describing, nor is the name of the delegate type meaningful as to what instances are supposed to do. Therefore, refrain from using them in contexts where their purpose is not absolutely self-evident.
The latter solution is the one most people posted. I'm also mentioning it in my answer for the sake of completeness.
The solution involves Delegates, which are used to store methods to call. Define a method taking a delegate as an argument,
public static T Runner<T>(Func<T> funcToRun)
{
// Do stuff before running function as normal
return funcToRun();
}
Then pass the delegate on the call site:
var returnValue = Runner(() => GetUser(99));
You should use a Func<string, int> delegate, that represents a function taking a string argument and returning an int value:
public bool RunTheMethod(Func<string, int> myMethod)
{
// Do stuff
myMethod.Invoke("My String");
// Do stuff
return true;
}
Then invoke it this way:
public bool Test()
{
return RunTheMethod(Method1);
}
While the accepted answer is absolutely correct, I would like to provide an additional method.
I ended up here after doing my own searching for a solution to a similar question.
I am building a plugin driven framework, and as part of it I wanted people to be able to add menu items to the applications menu to a generic list without exposing an actual Menu object because the framework may deploy on other platforms that don't have Menu UI objects. Adding general info about the menu is easy enough, but allowing the plugin developer enough liberty to create the callback for when the menu is clicked was proving to be a pain. Until it dawned on me that I was trying to re-invent the wheel and normal menus call and trigger the callback from events!
So the solution, as simple as it sounds once you realize it, eluded me until now.
Just create separate classes for each of your current methods, inherited from a base if you must, and just add an event handler to each.
Here is an example Which can help you better to understand how to pass a function as a parameter.
Suppose you have Parent page and you want to open a child popup window. In the parent page there is a textbox that should be filled basing on child popup textbox.
Here you need to create a delegate.
Parent.cs
// declaration of delegates
public delegate void FillName(String FirstName);
Now create a function which will fill your textbox and function should map delegates
//parameters
public void Getname(String ThisName)
{
txtname.Text=ThisName;
}
Now on button click you need to open a Child popup window.
private void button1_Click(object sender, RoutedEventArgs e)
{
ChildPopUp p = new ChildPopUp (Getname) //pass function name in its constructor
p.Show();
}
IN ChildPopUp constructor you need to create parameter of 'delegate type' of parent //page
ChildPopUp.cs
public Parent.FillName obj;
public PopUp(Parent.FillName objTMP)//parameter as deligate type
{
obj = objTMP;
InitializeComponent();
}
private void OKButton_Click(object sender, RoutedEventArgs e)
{
obj(txtFirstName.Text);
// Getname() function will call automatically here
this.DialogResult = true;
}
If you want to pass Method as parameter, use:
using System;
public void Method1()
{
CallingMethod(CalledMethod);
}
public void CallingMethod(Action method)
{
method(); // This will call the method that has been passed as parameter
}
public void CalledMethod()
{
Console.WriteLine("This method is called by passing it as a parameter");
}
If the method passed needs to take one argument and return a value, Func is the best way to go. Here is an example.
public int Method1(string)
{
// Do something
return 6;
}
public int Method2(string)
{
// Do something different
return 5;
}
public bool RunTheMethod(Func<string, int> myMethodName)
{
// Do stuff
int i = myMethodName("My String");
Console.WriteLine(i); // This is just in place of the "Do more stuff"
return true;
}
public bool Test()
{
return RunTheMethod(Method1);
}
Read the docs here
However, if your method that is passed as a parameter does not return anything, you can also use Action. It supports up to 16 paramaters for the passed method. Here is an example.
public int MethodToBeCalled(string name, int age)
{
Console.WriteLine(name + "'s age is" + age);
}
public bool RunTheMethod(Action<string, int> myMethodName)
{
// Do stuff
myMethodName("bob", 32); // Expected output: "bob's age is 32"
return true;
}
public bool Test()
{
return RunTheMethod(MethodToBeCalled);
}
Read the documentation here
Here is an example without a parameter:
http://en.csharp-online.net/CSharp_FAQ:_How_call_a_method_using_a_name_string
with params:
http://www.daniweb.com/forums/thread98148.html#
you basically pass in an array of objects along with name of method. you then use both with the Invoke method.
params Object[] parameters
class PersonDB
{
string[] list = { "John", "Sam", "Dave" };
public void Process(ProcessPersonDelegate f)
{
foreach(string s in list) f(s);
}
}
The second class is Client, which will use the storage class. It has a Main method that creates an instance of PersonDB, and it calls that object’s Process method with a method that is defined in the Client class.
class Client
{
static void Main()
{
PersonDB p = new PersonDB();
p.Process(PrintName);
}
static void PrintName(string name)
{
System.Console.WriteLine(name);
}
}
I don't know who might need this, but in case you're unsure how to send a lambda with a delegate, when the function using the delegate doesn't need to insert any params in there you just need the return value.
SO you can also do this:
public int DoStuff(string stuff)
{
Console.WriteLine(stuff);
}
public static bool MethodWithDelegate(Func<int> delegate)
{
///do stuff
int i = delegate();
return i!=0;
}
public static void Main(String[] args)
{
var answer = MethodWithDelegate(()=> DoStuff("On This random string that the MethodWithDelegate doesn't know about."));
}
Tried searching online for this but no luck so far
Basically I allow the user create an expression of choices such as
TargetHealthLessThen20
TargetAboutToUsePotion
These are stored against an enum and then stored in database as a string expression such as
"TargetHealthLessThen20 || TargetAboutToUsePotion"
now I have methods for each enum to check its conditon i.e
public bool IsTargetHealthLessThen20(Target target)
{
// do login
}
public bool IsTargetAboutToUsePotion(Target target)
{
// do login
}
I want to be able to write an If statement that was dynamic to call these methods and put in the conditons such as
if("IsTargetHealthLessThen20(target) || IsTargetAboutToUsePotion(target)")
{
// Perform Action
}
Any ideas on best way of going about this?
While I wouldn't necessarily recommend the following due to performance reasons, it will do what you want.
If you are always applying your target and only your target, you can predefine a class of evaluative methods and then pass in a list of string method names to evaluate against those methods.
void Main()
{
var inputs = new List<string>();
inputs.Add("MethodA");
inputs.Add("MethodB");
var results = Evaluate(inputs, "target");
Console.WriteLine(results);
}
public bool Evaluate(List<string> predicates, string target)
{
var methods = new Methods();
var tempResult = false;
foreach (var pred in predicates)
{
var method = methods.GetType().GetMethod(pred);
if (method == null)
throw new InvalidOperationException(
string.Format("Unknown method {0}.", pred));
tempResult = (bool)typeof(Methods).GetMethod(pred).Invoke(methods, new [] {target});
if (!tempResult) break;
continue;
}
return tempResult;
}
public class Methods
{
public bool MethodA(string target)
{
return target == "target";
}
public bool MethodB(string target)
{
return target == "not a target";
}
}
This particular Evaluate function will evaluate AND conditions. You would need to change your evaluative logic for OR conditions. You could in theory inspect your strings and call a different method depending on the operators in the strings.
EDIT
A second option that would avoid reflection would be to create a Dictionary that maps your string names for your methods to the methods themselves. This would allow you to achieve the same result without reflection, although you would have to keep your dictionary in sync. On the flip side, you gain and additional compile-time check without the reflection overhead.
private static readonly Methods _methodsInstance = new Methods();
private static Dictionary<string, Func<string, bool>> _methods = new Dictionary<string, Func<string, bool>>()
{
{ "MethodA", _methodsInstance.MethodA },
{ "MethodB", _methodsInstance.MethodB },
};
public bool Evaluate(List<string> predicates, string target)
{
var tempResult = false;
foreach (var pred in predicates)
{
tempResult = _methods[pred](target);
if (!tempResult) break;
continue;
}
return tempResult;
}
I think it's diffcult. Because you don't know the target parameter value. if you know the parameter value, you can use the reflect invoke the method by expression string.
I think I have just the answer you're looking for, because I needed the nearly exact same thing in the past:
What you have there is C# code, so you need to treat it like what it is :)
Create an interface like
interface ICondition { bool Evaluate(); }
Now use the text you have there to compile it into a class.
Like this:
using YourProgramNamespace;
class myCondition : ICondition
{
bool Evaluate() { return {0} ; }
}
To pass more parameters just change the interface to allow for the matching parameters.
If you don't want multiple interfaces just make it like this:
using YourProgramNamespace;
class myCondition : ICondition
{
bool Evaluate(params object[] parameters) { return {0} ; }
}
In your text you then just write it like this:
TargetHasLessThan20Hp((TargetType)parameters[0])
Where you replace the {0} with the condition text you already have.
Use the C# compiler to compile the code.
http://msdn.microsoft.com/de-de/library/microsoft.csharp.csharpcodeprovider%28v=vs.110%29.aspx
There are more than enough tutorials on how to use it and it's usage is not that hard.
When you have compiled the class into a Dll load it and find the type with reflection, this is also not hard and there are tons of tutorials out there. Just use yourAssembly.GetTypes() and go from there
Use Activator.CreateInstance to instantiate the type you have
Then just call the evaluate function and it will return true or false.
For better performance don't compile each time until the condition text actually changes.
Need more info? Just ask and I'll edit my answer or post it in the comments.
Is it possible to pass a function (like let's say sin() ) via string and then use it as int?
Like: (main idea only)
public int getfunc(String func)
{
return res_of(func)
}
I tried playing around with string of "Math.sin(0)"
but couldn't print the 0...
I could predefine the math functions since I only need 1 and then it becomes extremely simple as I only pass the int value for the function to work on, but I thought may-hap there is a way to keep it more generic.
I do not want to use mapping of the functions I want to keep it dynamic....
is ther a way of doing so?
I'd like to offer an alternative approach that you may not have considered.
You could use a delegate instead of passing a string; that way, you won't need any reflection.
There's a predefined delegate type in C# called Func<> which lets you easily define the return type and parameter types of a method that you want to pass as a delegate.
For example, the Func<> for Math.Sin(double) would be Func<double, double> because Math.Sin() returns a double and takes a double parameter.
An example will make this clearer:
using System;
namespace Demo
{
internal class Program
{
private void run()
{
Func<double, double> f1 = Math.Sin;
Func<double, double> f2 = Math.Cos;
double r1 = runFunc(f1, 1.0);
double r2 = runFunc(f2, 2.0);
Console.WriteLine(r1);
Console.WriteLine(r2);
}
private static double runFunc(Func<double, double> func, double parameter)
{
return func(parameter);
}
private static void Main()
{
new Program().run();
}
}
}
Try using http://www.csscript.net/
dynamic script = CSScript.Evaluator
.LoadCode(#"using System;
public class Script
{
public int Sum(int a, int b)
{
return a+b;
}
}");
int result = script.Sum(1, 2);
Declare the method like this:
public int DoCalculation(Func<double, double> func, double a)
{
return Convert.ToInt32(func(a));
}
Then use it like this:
int result = DoCalculation(Math.Sin, 3.3);
In our application we use the .NET integrated C# compiler.
This is some work to do but straight-forward to implement.
Here's an answer with a lot more details on that.
We use this in our companies production.
I'm returning values from an Entity object. Some of them are String typed and some are not. Right now, I did a quick solution as follows.
private String GetStringValue(Entity entity, String attribute, String substitute = "")
{
if(entity.Contains(attribute)
return entity[attribute] as String;
return substitute;
}
private String GetIntValue(Entity entity, String attribute, int substitute = 0)
{
if(entity.Contains(attribute)
return entity[attribute] as int;
return substitute;
}
Then I remembered that there's a syntax for generic typing (something like <TypeX>). My question is, however, if there's a point to start changing the existing code. I'll need to change the signature of the method in two places (return type and substitute type) but I fear that I'll need to do some complex coding inside the method as well.
On the other hand, I'd have a nice way to treat all the types possible (and I have a hunch we'll be working with more than strings and integers.
You will have to change the signature of the method in three places, because you also have to add the generic parameter:
private T GetValue<T>(Entity entity, String attribute, T substitute)
Within the method, there's no real need for any complex coding; replacing your current occurrences of string or int, respectively, with T, should suffice. (Note that the as operator can only be applied if you restrict T to reference types - which you probably don't want to do, because int is a value type).
Note that there are two issues with this method that you might consider drawbacks:
This generic method will support "all the types possible", but it will also support any types impossible (users are free to specify whatever type they like for T, and there is no way to restrict T while still supporting both string and int.
You cannot specify arbitrary default substitute values for each type. What you can do is declare a default value for substitute, namely default(T), but at least for string, that is not an empty string, but null.
You are right "something like" is the generic method. Check out generic methods there.
Next method looks good for your purpose.
private static T GetValue<T>(Entity entity, string attribute, T defaultValue)
{
if (!entity.Contains(attribute))
return defaultValue;
return (T)entity[attribute];
}
EDIT: updated according of the w0lf's comment.
If you don't want to change method signature, you can write a generic function and call it from all of these non generic versions.
private String GetStringValue(...){
return GetValue<String>(...);
}
By the way, you are looking for Generic methods
For e.g (from msdn)
static void Swap<T>(ref T lhs, ref T rhs)
{
T temp;
temp = lhs;
lhs = rhs;
rhs = temp;
}
...
Swap<int>(ref a, ref b);
or just
Swap(ref a, ref b); //type int is infered based on type of arguements and method signature
What class is Entity? Assuming it's a custom class, make it also generic, then this works:
private T Get<T>(Entity<T> entity, T attribute, T substitute = default(T))
{
if (entity.Contains(attribute))
return entity[attribute];
return substitute;
}
You can retrieve the value in this way:
var entity = new Entity<string>();
string val = Get<string>(entity, "attr", "subst");
You should define your Entity<T> class:
public class Entity<T>
{
// TODO: implement
public T this[string i] { get; set; }
// TODO: implement
internal bool Contains(string attribute)
{
return true;
}
// TODO: implement
// other properties and methods
}
And you may use a generic method:
private T GetStringValue<T>(Entity<T> entity, String attribute, T substitute = default(T))
{
if (entity.Contains(attribute))
return entity[attribute];
return substitute;
}
If it is possible to generalize the code inside a method I would absolutely recommend to use it in a generic way. It makes the class smaller, better readable and you just have to change one method if requirements change. Your method looks like it can be made generic easily.
private T GetIntValue<T>(Entity entity, String attribute, T substitute = default(T))
{
if(entity.Contains(attribute))
return (T)entity[attribute];
return substitute;
}
If there would be some more logic to execute you could also use a dictionary with functions for the different types:
private IDictionary<Type, Func<Entity, string, object>> actions;
private void InitActions()
{
actions = new Dictionary<Type, Func<Entity, string, object>>
{
{
typeof (string), (entity, attribute) =>
{
// this could be your custom code for string
return entity[attribute];
}
},
{
typeof (int), (entity, attribute) =>
{
// this could be your custom code for int
return entity[attribute];
}
}
};
}
private T GetIntValue<T>(Entity entity, String attribute, T substitute = default(T))
{
if (entity.Contains(attribute) && actions.ContainsKey(typeof (T)))
{
Func<Entity, string, object> action = actions[typeof (T)];
return (T)action(entity, attribute);
}
return substitute;
}
I'm trying to use a method group in a lambda expression, like this:
public class Foo { public void Hello(string s) { } }
void Test()
{
// this works as long as Hello has a void return type
Func<Foo, Action<string>> a = foo => foo.Hello;
}
When I change the return type of Hello to int, however, I get
'Bar.Hello(string)' has the wrong return type.
I've tried playing around with Func in place of Action, but that seems to prevent me from using the method group syntax.
Any ideas?
(My goal, fwiw, is to be able to refer to numerous methods that have different return types and lots of string arguments. I don't even intend to call them - I just want to reflect over their attributes. I do like the safety of lambdas, however, versus just typing in method name strings.)
Edit: to clarify my reasons for wanting to use Action<string>: int in my example may be any of a number of types. I tried templating that type --
void Set<T>(Func<Foo, Func<string, T>> a) { }
void Test() { Set(foo => foo.Hello); } // fails
-- but the compiler can't derive T (presumably for the same reasons I can't overload on return type?).
Any other ideas? I'm not opposed in this case to some crazy reflection as long as I can get the compiler to check the name of that method group.
When it has a non-void return type, it's no longer compatible with Action<string>. In other words, this would fail too:
int Foo(string s) { return 10; }
// Error: wrong return type
Action<string> action = new Action<string>(Foo);
For the reasons why this isn't allowed, see Eric Lippert's blog post on "The void is invariant".
You should be able to use method group syntax like this:
public class Foo { public int Hello(string s) { return 10; } }
void Test()
{
Func<Foo, Func<string, int>> a = foo => foo.Hello;
}
That works for me in both VS2008 and VS2010. There have been some changes to method group conversions and type inference for C# 4 - the details escape me unfortunately - but I don't believe this case is affected by those changes.
With a void return type, foo.Hello is an Action<string>. With an int return type, it's now a Func<string, int>.
To handle multiple return types — and assuming you don't need to do anything with the return value — you can trivially wrap non-void functions thus:
Func<Foo, Action<string>> a = foo => s => foo.Hello(s);