How to call an appropriate method by string value from collection? - c#

I have a collection of strings. For example,
string[] coll={"1", "2", "3" ..."100"..."150"...}
and I have respective methods for the string collection such as
void Method1, void Method2, void Method100
I select appropriate method like that:
string selector=string.Empty;
switch(selector)
{ case "1":
MethodOne();
break;
........
case "150":
Method150();
break;
}
The above code is really bored and I will have more string elements in the string collection {"150" ... "250"...}.
How to make like that:
string sel=col[55];
if(sel!=null)
// call here the respective method(method55)
I do not want to use switch operator cause it gives rise to surplus of code.

Solution 1:
Use a delegate mapping. This is the faster solution.
private static Dictionary<string, Action> mapping =
new Dictionary<string, Action>
{
{ "1", MethodOne },
// ...
{ "150", Method150 }
};
public void Invoker(string selector)
{
Action method;
if (mapping.TryGetValue(selector, out method)
{
method.Invoke();
return;
}
// TODO: method not found
}
Solution 2:
Use reflection. This is slower and is appropriate only if your methods have strict naming (eg. 1=MethodOne 150=Method150 will not work).
public void Invoker(string selector)
{
MethodInfo method = this.GetType().GetMethod("Method" + selector);
if (method != null)
{
method.Invoke(this, null);
return;
}
// TODO: method not found
}

You can declare a dictionary with your keys and actions like
Dictionary<string, Action> actions = new Dictionary<string, Action>()
{
{ "1", MethodOne },
{ "2", ()=>Console.WriteLine("test") },
............
};
and invoke it as
actions["1"]();
PS: Presuming method void MethodOne(){ } is declared somewhere.

You can use dynamic invocation
var methodName = "Method" + selector;
var method = this.GetType().GetMethod(methodName);
if (method == null)
{
// show error
}
else
method.Invoke(this, null);

Related

Get info about caller and parameters (name and value) of a Func<T> delegate

I have a class that expose a public method (ExecuteJob) that accept a Func delegate and run it asyncronusly. I need to know info about:
The Caller (class and method name that invoke ExecuteJob)
List of parameter and it's value used to call Func delegate
If it's possible, before run Func delegate, set value of specific parameter of this delegate
Example Code
public static class JobHandlerManager
{
public static async Task ExecuteJob<T>(Func<T> MetodoDaEseguire)
{
Params parOfMethod = MetodoDaEseguire.GetMethodParams();
// here I need to get info about above points
string Caller = "ExternalMethod"
string Parameters = "\"par1\" = \"a\", \"par2\" = 10, \"par3\" = [\"x\", \"y\", \"z\"] "
int JobID = CalculateJobId();
parOfMethod = parOfMetho.add(JobID);
Func<T> NewMethod = MetodoDaEseguire(parOfMethod);
Task.Run(MetodoDaEseguire);
}
}
public void DoStuff(string par1, int par 2, string[] arraypar, int JobID)
{
// JobID is set by JobHandlerManager.ExecuteJob
}
public void ExternalMethod()
{
JobHandlerManager.ExecuteJob(() => DoStuff("a", 10, new string[] {"x", "y", "z"}));
}
In provided case you can achieve at least parts of this using expression trees and CallerMemberNameAttribute:
public static int DoStuff(string par1, int par2, string[] arraypar, int JobID)
{
// JobID is set by JobHandlerManager.ExecuteJob
return 1;
}
public static void ExternalMethod()
{
JobHandlerManager.ExecuteJob(() => DoStuff("a", 10, new string[] { "x", "y", "z" },1));
}
public static class JobHandlerManager
{
public static T ExecuteJob<T>(Expression<Func<T>> MetodoDaEseguire, [CallerMemberName]string caller = "")
{
Console.WriteLine(caller); // will print "ExternalMethod"
var mc = MetodoDaEseguire.Body as MethodCallExpression;
Console.WriteLine(string.Join(", ", mc.Method.GetParameters().Select(p => p.Name))); // will print "par1, par2, arraypar, JobID"
Console.WriteLine(string.Join(", ", mc.Arguments)); // will print ""a", 10, new [] {"x", "y", "z"}, 1"
return MetodoDaEseguire.Compile()();
}
}
And calling ExternalMethod(); will print:
ExternalMethod
par1, par2, arraypar, JobID
"a", 10, new [] {"x", "y", "z"}, 1
But beware of performance and closures (i.e. to get actual values passed from local variables, fields, etc. more work will be needed to be done).
To get caller class you can try to look into Environment.StackTrace or CallerFilePathAttribute for example (depends on your needs).
UPD
To replace some of the arguments you can do something like this:
var newArgs = mc.Arguments.ToList();
var ardIdToReplace = newArgs.Count - 1; // find somehow index of replaced argument
newArgs[ardIdToReplace] = Expression.Constant(42);
var newLambda = Expression.Lambda<Func<T>>(Expression.Call(mc.Method, newArgs));
return newLambda.Compile()();
Bear in mind this also can be quite error prone cause due to custom handling of expression you loose a lot of compile time safety (user can pass a lot of more then my solution can support).
I found by my self a solution form my last problem, including this two method inside ma static class.
private static object GetArgumentValue(Expression element)
{
if (element is ConstantExpression)
{
return (element as ConstantExpression).Value;
}
var l = Expression.Lambda(Expression.Convert(element, element.Type));
return l.Compile().DynamicInvoke();
}
private static string[] GetParamArgumentsValue(ReadOnlyCollection<Expression> Arguments)
{
List<string> ParamArgumentsValue = new List<string>();
foreach (var arg in Arguments)
{
ParamArgumentsValue.Add(JsonConvert.SerializeObject(GetArgumentValue(arg)));
}
return ParamArgumentsValue.ToArray();
}

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

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

How to use an array of strings to handle the cases in a switch statement in C#?

I have an array
public static string[] commands =
{
"command1",
"command2",
"command3",
"command4",
"command5",
"command6",
"command7"
};
I want to use the array in the function
public static bool startCommand (string commandName) {
//stuff
if (commandName == commands[0]) {
//stuff
return true;
}
else {
//stuff
switch (commandName) {
case commands [1]:
//stuff
break;
case commands [2]:
//stuff
break;
case commands [3]:
//stuff
break;
case commands [4]:
//stuff
break;
case commands [5]:
//stuff
break;
case commands [6]:
//stuff
break;
default:
return false;
}
//do stuff
return true;
}
}
The error that this is giving me is "A constant value is expected" for each of the cases.
I could use if and else statements, but I think the switch statement looks better for this.
Unless I've missed my mark, my array is of constant strings, so this should work. Any help would be appreciated. Sorry if this is a newb question, I've been programming with C# for about four days.
What you're looking for is the Dictionary<TKey, TValue> type. A Dictionary is basically a collection of Key-Value pairs, something we can take advantage of for what you're attempting to achieve.
Using the example you've given, the implementation would look like this:
Dictionary<string, Action> commandsDictionary = new Dictionary<string, Action>();
commandsDictionary.Add("Command1", () => Console.WriteLine("Command 1 invoked"));
commandsDictionary.Add("Command2", () => Console.WriteLine("Command 2 invoked"));
commandsDictionary["Command2"].Invoke();
// Command 2 invoked
As you'll have noticed, I've introduced the an Action delegate without any parameters.
To introduce a parameter, just specify it as a type argument, like this: Action<int>
Dictionary<string, Action<int>> commandsDictionary = new Dictionary<string, Action<int>>();
commandsDictionary.Add("Command1", (i) => Console.WriteLine("Command {0} invoked", i));
commandsDictionary["Command1"].Invoke(1);
// Command 1 invoked
If you want to return a value from the delegate you're invoking, use the Func delegate, an easy to remember rule with Func is that the last type parameter is always the type being returned, so Func<int, string> would be equivalent to a method with the following signature public string Foo(int i)
Dictionary<string, Func<int, string>> commandsDictionary = new Dictionary<string, Func<int, string>>();
commandsDictionary.Add("Command1", (i) => { return string.Format("Let's get funky {0}", i); });
string result = commandsDictionary["Command1"].Invoke(56963);
Console.WriteLine (result);
// Let's get funky 56963
Reference
I've added this section to aid those who do not yet know what a delegate is... it's all actually rather simple.
Delegates
A Delegate is a Type that represents references to methods. They're just like variables that you declare to reference objects, except instead of objects, they reference methods.
A delegate can be instantiated with a named method or an anonymous function such as a lambda expression (which is the type I've demonstrated above).
The Action Delegate
The Action Delegate has a return type of void and defines its signature with type parameters.
void Example()
{
// Named method
this.NamedActionDelegate = NamedMethod;
this.NamedActionDelegate.Invoke("Hi", 5);
// Output > Named said: Hi 5
// Anonymous Function > Lambda
this.AnonymousActionDelegate.Invoke("Foooo", 106);
// Output > Anonymous said: Foooo 106
}
public Action<string, int> NamedActionDelegate { get; set; }
public Action<string, int> AnonymousActionDelegate = (text, digit) => Console.WriteLine ("Anonymous said: {0} {1}", text, digit);
public void NamedMethod(string text, int digit)
{
Console.WriteLine ("Named said: {0} {1}", text, digit);
}
The Func Delegate
The Func Delegate is similar to the Action Delegate the difference being that Func never returns void and thus will always require at least 1 type argument and as mentioned earlier, the type argument specified last dictates the return type of the delegate.
void Example()
{
// Named method
this.NamedFuncDelegate = NamedMethod;
string namedResult = this.NamedFuncDelegate.Invoke(5);
Console.WriteLine (namedResult);
// Output > Named said: 5
// Anonymous Function > Lambda
string anonyResult = this.AnonymousFuncDelegate.Invoke(106);
Console.WriteLine (anonyResult);
// Output > Anonymous said: 106
}
public Func<int, string> NamedFuncDelegate { get; set; }
public Func<int, string> AnonymousFuncDelegate = (digit) => { return string.Format("Anonymous said: {0}", digit); };
public string NamedMethod(int digit)
{
return string.Format ("Named said: {0}", digit);
}
If you want to use the switch with the array commands, instead use of compare with the items of commands use the index statement like this:
public static string[] commands =
{
"command1",
"command2",
"command3",
"command4",
"command5",
"command6",
"command7"
};
public static bool startCommand(string commandName)
{
var index = Array.IndexOf(commands, commandName);
//stuff
if (index == 0) // commands[0]
{
//stuff
return true;
}
else
{
//stuff
switch (index)
{
case 1: // commands[0]
//stuff
break;
case 2: // commands[2]
//stuff
break;
case 3: // commands[3]
//stuff
break;
case 4: // commands[4]
//stuff
break;
case 5: // commands[5]
//stuff
break;
case 6: // commands[6]
//stuff
break;
default:
return false;
}
//do stuff
return true;
}
}
To summarize as an answer, change it to something like this:
Dictionary<string, Action> commands = new Dictionary<string,Action>();
commands.Add("command1", () => {});
commands.Add("command2", () => { });
commands.Add("command3", () => { });
Action action = null;
commands.TryGetValue(commandName, out action);
if (action != null)
action();
You can make your dictionary static, or possibly readonly if you want:
static void Command1() { }
static void Command2() { }
static readonly Dictionary<string, Action> commands = new Dictionary<string, Action>(){
{ "command1", Command1 },
{ "command2", Command2 }
};
Assuming you are ok with constant strings, what about defining a static class:
public static class COMMANDS
{
public const string COMMAND1 = "command1";
public const string COMMAND2 = "command2";
public const string COMMAND3 = "command3";
public const string COMMAND4 = "command4";
public const string COMMAND5 = "command5";
public const string COMMAND6 = "command6";
public const string COMMAND7 = "command7";
}
and then use it with the switch statement:
//stuff
if (commandName == COMMANDS.COMMAND1)
{
//stuff
return true;
}
else
{
//stuff
switch (commandName)
{
case COMMANDS.COMMAND2:
//stuff
break;
case COMMANDS.COMMAND3:
//stuff
break;
case COMMANDS.COMMAND4:
//stuff
break;
case COMMANDS.COMMAND5:
//stuff
break;
case COMMANDS.COMMAND6:
//stuff
break;
case COMMANDS.COMMAND7:
//stuff
break;
default:
return false;
}
//do stuff
return true;
}
using System;
using System.Reflection;
namespace CommandExample
{
class Program
{
static void Main()
{
var cmdName = "Command1";
// Create an instance of the command class using reflection
Type type = Assembly.GetExecutingAssembly().GetType("CommandExample." + cmdName);
if (type == null) { /* Cannot find command. Handle error */ }
var cmd = Activator.CreateInstance(type) as ICommand;
cmd.Exec();
}
}
interface ICommand
{
void Exec();
}
class Command1 : ICommand
{
public void Exec()
{
Console.WriteLine("Executing Command1");
}
}
}

Can a delegate take a generic as a parameter

I've created a class that works with my cache to get cached items. If the items are not cached then it calls a function to get the actual value.
This class has eight methods, all with almost identical code except for the function they call. I've created a function called GetObject which takes a delegate to call if it can't find an item in the class.
I can't get my code to compile because of the following error:
Argument 2: cannot convert from
'System.Collections.Generic.List<string>' to
'MyFunction<System.Collections.Generic.List<string>>'.
Am I doing something wrong or am I'm trying to do something that can't be done?
Here's the code I'm trying.
public delegate T MyFunction<T>(string s);
public T GetCultures<T>(string s) where T : class {
return NewListOfStrings(s) as T;
}
public List<string> NewListOfStrings(string s) {
return new List<string> { s };
}
public List<string> GetListOfStrings(string sitename) {
string key = cachingService.CreateValidKey("stringvalue");
//This is the line that fails to compile
var foundItems = GetObject<List<string>>(key,
GetCultures<List<string>>(sitename));
return foundItems;
}
public T GetObject<T>(string key, MyFunction<T> f) where T : class {
T foundItems = (T)cachingService.GetCachedItem(key);
if (foundItems == null) {
lock (key) {
foundItems = (T)cachingService.GetCachedItem(key);
if (foundItems == null) {
foundItems = f as T;
if (foundItems != null) {
cachingService.SetCachedItem(key, foundItems, 5,
Constants.MINUTES);
}
}
}
}
return foundItems;
}
Solution
public T GetObject<T>(string key, Func<T> getFromRepository) where T : class {
T foundItems = (T)cachingService.GetCachedItem(key);
if (foundItems == null) {
lock (key) {
foundItems = (T)cachingService.GetCachedItem(key);
if (foundItems == null) {
foundItems = getFromRepository() as T;
if (foundItems != null) {
cachingService.SetCachedItem(key, foundItems, 5,
Constants.MINUTES);
}
}
}
}
return foundItems;
}
public AreaModels.Site GetSiteByName(string sitename) {
string key = cachingService.CreateValidKey(
string.Format("Site_{0}", sitename));
return GetObject<AreaModels.Site>(key,
() => efRepository.GetSiteByName(sitename));
}
public List<AreaModels.Culture> GetCulturesForSite(string sitename) {
string key = cachingService.CreateValidKey(
string.Format("Cultures_{0}", sitename));
return GetObject<List<AreaModels.Culture>>(key,
() => efRepository.GetCulturesForSite(sitename));
}
public List<AreaModels.Resource> Resources(string sitename, int appId) {
string key = cachingService.CreateValidKey(
string.Format("ResourcesFor{0}", sitename));
return GetObject<List<AreaModels.Resource>>(key,
() => efRepository.GetResourcesBySiteAndAppId(sitename, appId));
}
You're passing the result of the function rather than the function itself. You can use a lambda like so:
var foundItems = GetObject<List<string>>(key,
name => GetCultures<List<string>>(sitename));
You also have this line:
foundItems = f as T;
Here you're trying to cast the function itself to its return type, which won't work. Instead you could do:
foundItems = f(name);
But now your problem is that you'd have to pass the name into GetObject, because otherwise it won't be accessible where it's needed. The reason for this is there's a mismatch between MyFunction, which takes a string, and what you actually want, which is a function that can be evaluated within GetObject without needing the name parameter to be passed in.
So what you should really do is change your delegate to:
public delegate T MyFunction<T>();
Or alternatively get rid of the delegate altogether and have the f parameter be a Func<T>.
With either of these options, you can pass in the lamba with no parameter required:
var foundItems = GetObject<List<string>>(key,
() => GetCultures<List<string>>(sitename));
And evaluate it like:
foundItems = f();
Note that it's a bit roundabout to create a lambda to pass it into another method just to then evaluate it, rather than just passing the result in directly. So unless there's some reason that you need to do this in some cases, you might instead want to change the f parameter to take a type T instead. In this case I suspect you're doing it to lazily evaluate the function so that you don't have to evaluate if the result is already cached. That would probably be a valid reason, assuming you're not optimizing for performance prematurely.
You aren't creating a delegate. You are actually evaluating the method before calling GetObject. Easily fixed:
var foundItems = GetObject<List<string>>(key,
name => GetCultures<List<string>>(name));
Note also that it isn't obvious what you want to do with sitename in this scenario; you might instead mean this:
name => GetCultures<List<string>>(sitename));
Here's a complete example
public class TestDelegate
{
//You don't need generic here if you always return a list of string
public List<string> GetCulture(string s)
{
return new List<string> { s };
}
public T GetObject<T>(string key, Func<string, T> fn)
{
T foundItems = fn(key);
return foundItems;
}
public void Test()
{
List<string> test = GetObject("abc", x => GetCulture(x));
}
}
If you look at the method Test() and GetObject(), you can note 3 interesting things :
You don't have to specify the generic type on GetObject() because the compiler infer it from GetCulture()
The x parameter serves as an input to your delegate function, that way the method
GetObject can use the "key" and pass it to the delegate function.
I replace your delegate function by "Func" with a string input and a List output.

Getting values of a generic IDictionary using reflection

I have an instance that implements IDictionary<T, K>, I don't know T and K at compiletime, and want to get all elements from it. I don't want to use IEnumerable for some reason, which would be the only non-generic interface implemented by IDictionary.
Code I have so far:
// getting types
Type iDictType = instance.GetType().GetInterface("IDictionary`2");
Type keyType = iDictType.GetGenericArguments()[0];
Type valueType = iDictType.GetGenericArguments()[1];
// getting the keys
IEnumerable keys = (IEnumerable)dictType.GetProperty("Keys")
.GetValue(instance, null);
foreach (object key in keys)
{
// ==> this does not work: calling the [] operator
object value = dictType.GetProperty("Item")
.GetValue(instance, new object[] {key } );
// getting the value from another instance with TryGet
MethodInfo tryGetValue = iDictType.GetMethod("TryGetValue");
object[] arguments = new object[] { key, null };
bool hasElement = (bool)tryGetValue.Invoke(otherInstance, arguments);
object anotherValue = arguments[1];
}
I could also call TryGetValue, but I think it should be possible to call the [] operator. Can anybody help me?
It would be better to figure out the TKey / TValue, and switch into regular code via MakeGenericMethod - like so:
(edit - you could pass in the otherInstance as an argument too, if they are of the same type)
static class Program
{
static void Main()
{
object obj = new Dictionary<int, string> {
{ 123, "abc" }, { 456, "def" } };
foreach (Type iType in obj.GetType().GetInterfaces())
{
if (iType.IsGenericType && iType.GetGenericTypeDefinition()
== typeof(IDictionary<,>))
{
typeof(Program).GetMethod("ShowContents")
.MakeGenericMethod(iType.GetGenericArguments())
.Invoke(null, new object[] { obj });
break;
}
}
}
public static void ShowContents<TKey, TValue>(
IDictionary<TKey, TValue> data)
{
foreach (var pair in data)
{
Console.WriteLine(pair.Key + " = " + pair.Value);
}
}
}
Just for completion, even if Marc Gravell's solution is much nicer, this is the way how it works the way I already started:
object value = dictType.GetMethod("get_Item")
.Invoke(instance, new object[] { key });
This calls the [] operator of the dictionary.

Categories