So I'm trying to make a 2D game (C#) where the player has different skills that they can use. The problem is that I don't know how to call a function with the string containing the skill name. There is always another way to do it, which is by making a really long list full of if-statements to check if the skill is named something, but this seems far from ideal.
Let's say a skill is called "Skill1". Is there any way to call a function called Skill1() by using the string "Skill1"? It would really help with making the code look good.
Thanks in advance
What you're looking for are delegates (and more specifically a dictionary of delegates).
void Main()
{
var things = new Dictionary<string, Action>
{
{"Thing1", DoThing1},
{"Thing2", DoThing2},
{"Thing3", DoThing3},
};
things["Thing1"]();
things["Thing3"]();
things["Thing2"]();
}
public void DoThing1()
{
Console.WriteLine("In Do Thing 1");
}
public void DoThing2()
{
Console.WriteLine("In Do Thing 2");
}
public void DoThing3()
{
Console.WriteLine("In Do Thing 3");
}
For more information, search for Delegates, Actions and Funcs.
Delegates are a good option but if you want to keep it simple you can use switch statement instead of if statements and it will be easy to maintain.
It's basic but maybe it will help
static void Main(string[] args)
{
Console.WriteLine("call skill");
string _skill = Console.ReadLine();
CallSkills(_skill);
}
public static void CallSkills(string skillname)
{
switch (skillname)
{
case "skill1":
//call skill1 method
break;
case "skill2":
//call skill2 method
break;
case "skill3":
//call skill3 method
break;
case "skill4":
//call skill4 method
break;
case "skill5":
//call skill5 method
break;
default:
break;
}
}
An alternative to using a dictionary with delegates is to using a switch expression with delegates.
One possible approach is to create a method that associates all relevant skill names with the appropriate Skill* method, as well as using the discard pattern (_ => ...; here: _ => null) to define a default value for any skillName that does not match any defined skill names in the expression:
private static Action GetSkillAction(string skillName)
{
return skillName switch
{
"Skill1" => Skill1,
"Skill2" => Skill2,
_ => null
};
}
To make it easier to use that method, you could create a method to actually perform a skill (by skill name). This method handles receiving a non-existing skill by only calling the associated action if the action is unlike null:
public static void PerformSkillAction(string skillName)
{
var action = GetSkillAction(skillName);
if (action != null)
{
action();
}
}
Now, calling
PerformSkillAction("Skill1");
will result in a call to Skill1(), whereas calling
PerformSkillAction("Banana");
will not call anything.
Example fiddle here.
Related
I've been puzzling at this for some time and I'm sure there's an elegant solution... I just can't seem to find it.
I have a web API where the object type being acted on is set by a string parameter. I then need to call a number of generic methods based on that type. Basically what I have is a good old switch statement that I'm in danger of having to repeat several times over, so want to try to encapsulate it within a reusable method:
switch (ModuleName)
{
case "contacts":
return Method1<Contact>();
case "accounts":
return Method1<Account>();
default:
throw new Exception("ModuleName could not be resolved");
}
In other places I'll need to do the same thing but call Method2, Method3, Method4 etc.
I think I should be able to turn this into a method that takes a string and a delegate that accepts the generic type, but I'm stuck on how to construct that. Can anyone point me in the right direction?
Many thanks
Tim
Like Michael Randall says, generics need to be known at compile time. I think you need to reconsider how you encapsulate your business logic here. You could probably solve it like this:
class Example{
void Main(){
var method1 = new LogicMethod1();
TestCase("contacts", method1);
TestCase("Case2", method1);
var method2 = new LogicMethod2();
TestCase("contacts", method2);
TestCase("Case2", method2);
}
void TestCase(string moduleName, LogicBase logic){
switch(moduleName){
case "contacts" : logic.DoTheStuff<Contact>(); break;
case "accounts" : logic.DoTheStuff<Account>(); break;
}
}
}
abstract class LogicBase{
public abstract void DoTheStuff<T>();
}
class LogicMethod1 : LogicBase{
public override void DoTheStuff<T>(){
//Logic for your Method1
}
}
class LogicMethod2 : LogicBase{
public override void DoTheStuff<T>(){
//Logic for your Method2
}
}
I have a piece of code like this.
I write this because I love extension methods and lambda expression:
public static class TuneingRules
{
public static Func<HtmlNode, bool> IsNodeHavingClearNone = (node) =>
{
if (node.HasAttributes)
{
// HtmlAttribute atr = item.Attributes.Where(at => at.Name == "id" && at.Value == "hello").FirstOrDefault();
HtmlAttribute atr = node.Attributes.Where(at => at.Name == "style").FirstOrDefault();
if (atr != null)
{
return Regex.Match(atr.Value, "clear\\s*:\\s*none;").Success;
}
}
return true;
};
}
and extension method like this.
public static class ExtensionMethods
{
#region Ignoring Rules
public static bool Ignore(this HtmlNode Node, Func<HtmlNode,bool> func) {
return func(Node);
}
#endregion
}
now I have two approaches to use this piece of code..
1 case
if (!htmlNode.Ignore(TuneingRules.IsNodeHavingClearNone)){
//then do somethings
}
// here i am open to write lambda expression like this.
if (!htmlNode.Ignore( node => node.innerText =="" ){
//then do somethings
}
2 case
if (!TuneingRules.IsNodeHavingClearNone(htmlNode)) {
//then do something
}
I'm afraid that there are any performance issues if TuneingRules
has many static Func<HtmlNode,bool> objects. Do i need to refactor my code?
In the first case there is an extra call going through ignore function...
but in the second case i can call the function object directly.
Or is there another way to write this code in order to stick with lambda as well as extension methods?
No, there is no performance issue.
There will be a small performance hit the first time that you use the TuneingRules class, as the static constructor will be called and initialise all the static variables. That should however be quite small compared to the actual work that the function does.
Likewise, doing one extra method call is negligible compared to the work that the function does. It's even possible that the extension method call will be inlined by the JIT compiler, so that the executed code will actually do the same thing as in your second case.
I am trying to separate multiple parts of a function using Scopes but it doesn't see to work as shown in the following code
private static void Method()
{
{
//Code execution stops here. Although the return is defined inside a scope.
return;
}
{
Console.WriteLine("Whowaaah");
}
}
So what am i doing wrong ?
A block (i.e. a sequence of statements within curly braces) affects the visibility of variables defined within it, not program flow. What you are seeing is completely normal behavior.
Perhaps you are looking for separate methods?
It's OK to have many methods even if they contain only a line of code. This will be easier to maintain, especially since it sounds like you want to have one method that controls many other methods.
Two possible solutions for what you are doing could be this:
If you need to do multiple things:
private static void Method()
{
if(ShouldDoSenseless1())
{
Senseless1();
}
if(ShouldDoSenseless2())
{
Senseless2();
}
if(ShouldDoSenseless3())
{
Senseless3();
}
// etc.
}
Or, if you should only do a single thing among a list of choices:
private static void Method1()
{
var doWhatNow = WhatStepShouldBePerformed();
switch(doWhatNow)
{
case 1:
DoSenseless1:
break;
case 2:
DoSenseless1:
break;
case 3:
DoSenseless1:
break;
break;
// etc.
}
}
This question already has answers here:
Calling a function from a string in C#
(5 answers)
Closed 1 year ago.
I have a struct-array that contains details of different reports that can be run. Each report calls a different method and currently the program has to manually check the selected report value to specifically call the appropriate method.
I would like to store the method name in the struct-array and then have program invoke that method when there is match. Is this possible?
Currently:
if (this.cboSelectReport.Text == "Daily_Unload")
{
reportDailyUnload();
}
Ideally:
if(this.cboSelectReport.Text == MyArray[i].Name)
{
something(MyArray[i].MethodName);
}
UPDATE
I tired a number of the suggestions below and none of them worked. They didn't work probably due to how I have my program structured.
You can do it using reflection, but IMO it is too fragile: it introduces an invisible dependency on the name of the method that you call.
// Assuming that the method is static, you can access it like this:
var namedReportMethod = "MyReport1";
var reportMethod = typeof(ReporterClass).GetMethod(namedReportMethod);
var res = reportMethod.Invoke(null, new object[] {reportArg1, reportArg2});
A better approach would be to define a delegate based on your method, and store it in the struct/class instead of the method name.
delegate void ReportDelegate(int param1, string param2);
class Runner {
public static void RunReport(ReportDelegate rd) {
rd(1, "hello");
}
}
class Test {
static void TestReport(int a, string b) {
// ....
}
public static void Main(string[] args) {
Runner.RunReport(TestReport);
}
}
Instead of defining your own delegate types, you can use pre-defined ones based on Action<T1,T2,...> or Func<T1,T2,R>, depending on your need to return values from the reports.
Rather than storing the method name, you could store a delegate:
struct ReportInfo
{
public string Name { get; set; }
public Action Method { get; set; }
}
//...
MyArray[0] = new ReportInfo { Name = "Daily_Unload", Action = this.reportDailyUnload };
//...
if(this.cboSelectReport.Text == MyArray[i].Name)
{
MyArray[i].Method.Invoke();
}
Most people seem to prefer the alternative syntax where you can invoke a delegate as if it were a method, using a list of arguments in parentheses. I tend to avoid this, because it can be ambiguous whether the thing being invoked is a method or a delegate:
MyArray[i].Method();
In this case, we're invoking the delegate that is referred to by the Method property, but this code could also represent a call to a method called "Method". Confusing.
As for me, supporting simple switch is much easier than dealing with reflection, array of method names or delegates, and invoking that stuff:
switch (reportType)
{
case "Daily_Unload":
ReportDailyUnload();
break;
// ...
}
If all the methods share the same signature, one way would be to cache a delegate:
// initialize, maybe in a constructor
Dictionary<string, Action> nameDelegateMapping = new Dictionary<string, Action>();
// setup the delegates
nameDelegateMapping.Add("Daily_Unload", reportDailyUnload);
// ... add more methods here.
// later
string methodName = this.cboSelectReport.Text;
Action action;
if (nameDelegateMapping.TryGetValue(methodName, out action))
{
action();
}
else
{
// tell user the method does not exist.
}
Yes, what you are talking about is reflection. Here is an article on how to invoke a method. There is a lot you can find on reflection using google.
Add a delegate property to your struct (e.g. of type Action) then just invoke this delegate when you need it. Just set this property to the method you want to call when instantiating the struct instances.
Using a delegate and dictionary<string, delegate>
void Main()
{
var reports = new Dictionary<string, Report>
{
{"Daily_Unload", ReportDailyUnLoad}
};
var report = "Daily_Unload";
reports[report]();
}
delegate string Report();
string ReportDailyUnLoad()
{
return "daily unload report";
}
I have a class that creates a List<Action<int>> and holds on to them until a later time. This class can add and remove delegates from this list. This works well as long as people don't get too fancy. To combat anonymous function (which can't be removed) I check against the target of the delegate being null. If its null I throw an exception. The problem comes in when there is an anonymous delegate that contains a function. This has a target, but is just as unremovable. The simplified code below illustrates my issues
public class MyDelegateContainer
{
List<Action<int>> m_Container = new List<Action<int>>();
public void Add(Action<int> del)
{
if (del.Target == null)
{
throw new Exception("No static handlers");
}
m_Container.Add(del);
}
public bool Remove(Action<int> del)
{
if (m_Container.Contains(del))
{
m_Container.Remove(del);
return true;
}
return false;
}
}
public class MyFakeActionClass
{
public void Test(int temp) { }
}
class Program
{
static void Main(string[] args)
{
bool removed = false;
int counter = 0;
MyDelegateContainer container = new MyDelegateContainer();
MyFakeActionClass fake = new MyFakeActionClass();
//container.Add(p => { }); //Throws, this is what I want to happen
container.Add(fake.Test); //Works, this is the use case
removed = container.Remove(fake.Test); //Works, this is the use case
Debug.Assert(removed);
container.Add(p => { fake.Test(p); counter++; }); //Works but I would like it not to
removed = container.Remove(p => { fake.Test(p); counter++; }); //doesn't work
Debug.Assert(removed);
}
}
I need some way to identify
p => { fake.Test(p); counter++; }
is an anonymous function so I can throw if someone tries it. Thanks for any help
EDIT: I should note that I could use an Action<int> variable for the anonymous function and everything would work, but the Add and Remove are never in the same scope in practice.
In your example, the caller is responsible from removing the handler. So, if the caller doesn't want to remove the handler, it won't get removed, no matter if the handler is an anonymous delegate/lambda or not.
My suggestion is to change the delegate container to something like this:
public class MyDelegateContainer
{
List<Action<int>> m_Container = new List<Action<int>>();
public Action Add(Action<int> del)
{
m_Container.Add(del);
return new Action(() =>
{
m_Container.Remove(del);
});
}
}
The caller is still responsible for removing the handler, but instead of passing the handler again to the container, it receives a "token" that it can save and use later to remove the handler.
There is no way to reliably determine whether a function is "anonymous" because all functions have names to the CLR. It's only anonymous within the language that generates it, and that's compiler-dependent. You may be able to determine the algorithm used by Microsoft's current C# compiler, only to have it stop working on C# 5 or Mono.
Since you want to prevent users of your type from writing code that uses it wrong, you just need to throw an exception at some point that will make their program crash. What I would do is throw the exception in the Remove function when the target delegate isn't found. At that point your users will still get a crash and the only way to fix it is to write the delegate in some way that it's removable.
As an added bonus, you will catch bugs where somebody tries to remove delegates twice or that were never added in the first place. The code would look like this:
public bool Remove(Action<int> del)
{
if (m_Container.Contains(del))
{
m_Container.Remove(del);
return true;
}
throw new ArgumentException("Attempt to remove nonexistent delegate");
}
I would use introspection to check the names of the methods.
Anonymous methods typically have very predictable names. (I don't remember the exact format, but run some tests, and it should be obvious).
The drawback would be that if anyone created a non-anonymous method, but decided to name it anonMethod123 (or whatever the format is...) It would be falsely rejected.
Of course you can remove an anonymous method, you just need to have a reference to the same anonymous method.
var myAnonymousMethod = p => { fake.Test(p); counter++; };
container.Add(myAnonymousMethod);
removed = container.Remove(myAnonymousMethod);
As jonnii suggested in a comment, another way you could implement it is with a dictionary:
public class MyDelegateContainer
{
Dictionary<string, Action<int>> m_Container =
new Dictionary<string, Action<int>>();
public void Add(string key, Action<int> del)
{
m_Container.Add(key, del);
}
public bool Remove(string key)
{
return m_Container.Remove(key);
}
}
Then you could easily remove a known delegate at some arbitrary point in your code just by knowing what name was used to add it:
container.Add("fake.Test", fake.Test);
removed = container.Remove("fake.Test");
Debug.Assert(removed);
container.Add("anon", p => { fake.Test(p); counter++; });
removed = container.Remove("anon"); // works!
Debug.Assert(removed);
Old question I know but I would think that this would be a current (and future) proofed way of checking if a method is anonymous:
bool isAnonymous = !System.CodeDom.Compiler.CodeGenerator.IsValidLanguageIndependentIdentifier(del.Method.Name);
The runtime name of the anonymous method would have to be invalid if used at compilation time to ensure that it didn't clash.