Saving methods in a dictionary and use those methods on key match. - c#

Public void test(){
Console.WriteLine("Hello World");
}
Is it possible to save this method in a Dictionary, and call this method if Dicitionary contains the method's key value.
For example like this:
Hashtable table = new Hashtable<method, string>();
string input = "hello"
foreach(Dictionary.entry t in table){
if(input == t.Key){
//Call the t.value method.
}
}

class Program
{
private static void Main(string[] args)
{
var methods = new Dictionary<string, Action>();
//choose your poison:
methods["M1"] = MethodOne; //method reference
methods["M2"] = () => Console.WriteLine("Two"); //lambda expression
methods["M3"] = delegate { Console.WriteLine("Three"); }; //anonymous method
//call `em
foreach (var method in methods)
{
method.Value();
}
//or like tis
methods["M1"]();
}
static void MethodOne()
{
Console.WriteLine("One");
}
}

Yes, that's pretty easy: just use the Action delegate class:
Encapsulates a method that has no parameters and does not return a value.
var dict = new Dictionary<string, Action>();
dict.Add("hello", test);
var input = "hello";
dict[input]();
Demo

You can use Func to reference your methods and then call them in the loop
https://msdn.microsoft.com/en-us/library/bb549151%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396
And as #Lucas Trzesniewski answered your can use Action if your methods has no params

Related

How can I convert C# methods to compiled expressions?

I have the following class hierarchy:
public class Parent
{
[DebuggerStepThrough]
public void SayParent()
{
Console.WriteLine("Parent");
}
}
public sealed class Child : Parent
{
private static int _number = 0;
public Child() // May contain parameter i.e. not always parameterless consctructor
{
_number++;
}
[DebuggerStepThrough]
public void SayInstance()
{
Console.WriteLine("{0}-Say", _number);
}
[DebuggerStepThrough]
public void SayInstanceWithArg(string input)
{
Console.WriteLine("{0}-Say: {1}", _number, input);
}
[DebuggerStepThrough]
public static void SayStatic()
{
Console.WriteLine("{0}-Say", _number);
}
[DebuggerStepThrough]
public static void SayStaticWithArg(string input)
{
Console.WriteLine("{0}-Say: {1}", _number, input);
}
[DebuggerStepThrough]
public static Task SayStaticWithArgAndReturn(string input)
{
Console.WriteLine("{0}-Say: {1}", _number, input);
return null;
}
}
I need to be able to invoke any of these methods for a new instance of Child at any given time using reflection however to improve performance I need to resort to Delegate and/or Compiled Expressions.
So for example I can have:
var instanceOne = new Child();
var instanceTwo = new Child();
for which I would need to at runtime invoke these methods passing the arguments for those that need it. Note they include both static and instance methods with some accepting a parameter.
I have so far tried the following for the "SayInstance" method:
var sayInstanceMethod = typeof(Child)
.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)
.Where(m => m.GetCustomAttributes(typeof(DebuggerStepThroughAttribute), true).Length > 0)
.Where(t => t.Name == "SayInstance")
.First()
And then:
var instance = Expression.Constant(new Child()); // This should NOT be Constant, but then what should it be?!
var mCallInstance = Expression.Call(instance, sayInstanceMethod);
Action action = Expression.Lambda<Action>(mCallInstance).Compile();
action();
action(); // I need to pass in a new instance of Child to this method somehow
However I am getting:
1-Say
1-Say
instead of:
1-Say
2-Say
I suspect this is due to Expression.Constant but I cannot figure out how I could let it accept an instance of Child as its target at runtime.
I am hopeless when it comes to Expressions :-(
I am basically trying to implement what Jon Skeet mentions HERE either using Delegates or Compiled Expressions.
Any help is very much appreciated.
If I understood correctly, you need to use parameters, like this:
var instanceOne = new Child();
var instanceTwo = new Child();
var instance = Expression.Parameter(typeof(Child), "c"); // This should NOT be Constant, but then what should it be?!
var mCallInstance = Expression.Call(instance, sayInstanceMethod);
Action<Child> action = Expression.Lambda<Action<Child>>(mCallInstance, instance).Compile();
action(instanceOne);
action(instanceTwo); // I need to pass in a new instance of Child to this method somehow
Of course this will not output 1, 2 because your _number field is static and after creation of two instances has value 2 for both.
EDIT. If you need to call method with arguments - declare more parameters. For example if SayInstance has one argument of type string, then:
var instanceOne = new Child();
var instanceTwo = new Child();
var instance = Expression.Parameter(typeof(Child), "instance");
var arg = Expression.Parameter(typeof(string), "arg");
var mCallInstance = Expression.Call(instance, sayInstanceMethod, arg);
Action<Child,string> action = Expression.Lambda<Action<Child,string>>(mCallInstance, instance, arg).Compile();
action(instanceOne, "one");
action(instanceTwo, "two");
Try this out, this workf for me for a parameterless constructor, but this is that you need:
var instance = Expression.New(typeof(Child).GetConstructor(new Type[0]));
var mCallInstance = Expression.Call(instance, sayInstanceMethod);
Action action = Expression.Lambda<Action>(mCallInstance).Compile();
action();
action(); // I need to pass in a new instance of Child to this method someh

Calling a function dynamically based on an integer value

I want to call a different function without write if conditions like this:
if(a==1)
{
function1 ();
}
if(a==2)
{
function2 ();
}
if(a==3)
{
function3 ();
}
I want to call function like this :
Dictionary<int, function> functions= new Dictionary<int, function>();
functions.add(1, function1);functions.add(2, function2);functions.add(3, function3);
function[1];
How can I do this?
It seems your functions are actually actions, since a function returns a value. Also you don't have any method parameters, so you have to use Action.
Dictionary<int, Action> functions= new Dictionary<int, Action>();
functions.Add(1, function1);
functions.Add(2, function2);
functions.Add(3, function3);
function[1](); // <-- calling here needs parentheses
You can do something like the following
void Main()
{
Dictionary<int, Func<bool>> funcMap = new Dictionary<int, Func<bool>>() {
{1, Function1},
{2, Function2}
};
Console.WriteLine(funcMap[1]());
Console.WriteLine(funcMap[2]());
}
// Define other methods and classes here
bool Function1()
{
return true;
}
bool Function2()
{
return false;
}
This works because all functions have the same signature.
You can use lambdas to map functions with different signatures. Idea is the same as with Action:
var functions = new Dictionary<int, Action>
{
{ 1, () => method1(123) },
{ 2, () => method2(123, "123") },
};
functions[1](); // will call method1(123);
where functions are defined like this
void method1(int a) => Console.WriteLine(a);
void method2(int a, string b) => Console.WriteLine(a + b);

Anonymous method with return

Please tell me what is wrong and how to write annonymous method with return for this impementation
public class Test
{
public string Implisity { get; set; }
}
class Program
{
static void Main(string[] args)
{
/*Here is a problem */
var variable = Method(delegate(IList<string> i, List<string> j){ return new Test(){Implisity = i[j.IndexOf("Implisity")]}; });
}
public static List<T> Method<T>(Func<IList<string>, IList<string>, T> staff) { return new List<T>(){staff(new List<string>() {"1","2"}, new List<string>(){"Explisity","Implisity"})}; }
}
this is a flat method what as me need to make annonymous
public static Test Annonymous(IList<string> i, List<string> j)
{
var obj = new Test() { Implisity = i[j.IndexOf("Implisity")] };
return obj;
}
The problem is that the Method(...) method expects a Func<...> with different parameter types: it expects a method that takes two IList<string> objects, while you are making a delegate that takes an IList<string> and a List<string>
var variable = Method(
delegate(IList<string> i, IList<string> j) {
// ^
return new Test() {
Implisity = i[j.IndexOf("Implisity")]
};
}
);
To avoid issues like this in the future, use implicit typing, like this:
var variable = Method( (i, j) => new Test { Implisity = i[j.IndexOf("Implisity")] } );
In this example, the compiler knows what the parameter types of the function must be from the signature of the Method(...) method, so it implicitly assigns the types to i and j.
Try this:
var variable = Method((i, j) => new Test() { Implisity = i[j.IndexOf("Implisity")] });
A lambda expression is an unnamed method written in place of a delegate instance.
The compiler immediately converts the lambda expression to either:
A delegate instance.
An expression tree, of type Expression<TDelegate>, representing the
code inside the lambda expression in a traversable object model. This
allows the lambda expression to be interpreted later at runtime

Pass method into generic function and invoke it

im trying to write some kind a strongly typed routing system.
Imagine ive got some class with method A that takes and returns string
public class SomeClass
{
public string MethodA(string str)
{
return string.Format("SomeClass :: MethodA {0}", str);
}
}
And I want my main method to look like this
class Program
{
static void Main(string[] args)
{
var col = new SomeCollection();
col.Add<SomeClass>("url", c => c.MethodA("test")); //Bind MethodA to "url"
}
}
So my questions are:
What should be Add method signature?
How can I invoke MethodA in SomeCollection?
I guess it'll be something like
public class SomeCollection
{
public void Add<TController> (string url, Func<TController, string> exp)
{
// Add func to dictionary <url, funcs>
}
public void FindBestMatchAndExecute (Request request)
{
//Search url in collection and invoke it's method.
//Method params we can extract from request.
}
}
First, I think you want add instances of classes to a collection, not the types. Otherwise, you will need to use reflection. If my assumption is correct, then instead of declaring Func<x,y,z,...> just employ Action to be able to call any method with any numbers of parameters.
Dictionary<object, Action> tempDictionary = new Dictionary<object, Action>();
SomeClass someClass = new SomeClass();
tempDictionary.Add(someClass, () => someClass.MethodA("test"));
tempDictionary.Single(q => q.Key == someClass).Value();
but if you need return values, you will have to use Func instead of Action;
Dictionary<object, Func<string>> tempDictionary = new Dictionary<object, Func<string>>();
SomeClass someClass = new SomeClass();
tempDictionary.Add(someClass, () => someClass.MethodA("test"));
string temp = tempDictionary.Single(q => q.Key == someClass).Value();

o => o.MethodWithParameters | is it possible to use a method in a lambda without () and parameters

i have a method that takes as a parameter an expression because I need the method string name, and I don't care about the parameters of that method, is it possible to do that ?
I don't think that there is. You can however make a generic helper method that you can put in place of the parameters:
public T Any<T>(){
return default(T);
}
and you can call it like so:
YourMethod((YourClass yc) => yc.SomeMethod(Any<SomeClass>(), Any<SomeOtherClass>());
Yes, it's possible. Here is a concept proof test.
private static T RunExpression<T>(Expression<Func<T>> run )
{
var callExpression = (MethodCallExpression) run.Body;
var procedureName = callExpression.Method.Name;
Trace.WriteLine(procedureName);
foreach (var argument in callExpression.Arguments)
{
Trace.WriteLine(argument);
}
Trace.WriteLine(callExpression.Arguments.Count);
// Some really wicked stuff to assign out parameter
// Just for demonstration purposes
var outMember = (MemberExpression)callExpression.Arguments[1];
var e = Expression.Lambda<Func<object>>(outMember.Expression);
var o = e.Compile().Invoke();
var prop = o.GetType().GetField("s");
prop.SetValue(o, "Hello from magic method call!");
Trace.WriteLine(run.Body);
return default(T);
}
[TestMethod]
public void TestExpressionInvocation()
{
var action = new MyActionObject();
string s = null;
RunExpression(() => action.Create(1, out s));
Assert.AreEqual("Hello from magic method call!", s);
}
The easiest way to do this doesn't even use expression trees:
void Main()
{
Console.Out.WriteLine(GetNameOfMethod(new Action(Main)));
Console.Out.WriteLine(GetNameOfMethod(new Func<Delegate, string>(GetNameOfMethod)));
Console.Out.WriteLine(GetNameOfMethod(new Func<int, short, long>(AddNumber)));
Console.Out.WriteLine(GetNameOfMethod(new Action<int, short>(SwallowNumber)));
}
string GetNameOfMethod(Delegate d){
return d.Method.Name;
}
long AddNumber(int x, short y){ return x+y; }
void SwallowNumber(int x, short y){}
yields:
Main
GetNameOfMethod
AddNumber
SwallowNumber
I use this to build a BDD framework on http://storyq.codeplex.com.
Click here to see the file where I do this.
You can use this method without parameters but parentheses (even empty) are required, because without them you tell the compiler to access a property of that name.
You can use something like:
(credits go to klausbyskov)
But it's less verbose.
Also you will need to provide overloads for various argument lists.
[TestClass]
public class TestExpressions
{
public class MyClass
{
public bool MyMethod(string arg)
{
throw new NotImplementedException();
}
}
private static string UseExpression<T, Ta1>(Expression<Action<T,Ta1>> run)
{
return ((MethodCallExpression)run.Body).Method.Name;
}
[TestMethod]
public void TestExpressionParser()
{
Assert.AreEqual("MyMethod",
UseExpression<MyClass,string>((c,fakeString) => c.MyMethod(fakeString)));
}
}

Categories