Turning strings into commands? - c#

Is there a convenient way to take variables and convert them into something readable by the code? What I have right now reads somewhat like this:
int buttonNumber = 3;
int buttonShow = 0;
ButtonChanger bC;
void Update () {
if(buttonNumber == 1) {
buttonShow = bC.Change1;
}
if(buttonNumber == 2) {
buttonShow = bC.Change2;
}
if(buttonNumber == 3) {
buttonShow = bC.Change3;
}
What I would like to be able to do is more like this:
int buttonNumber = 3;
int buttonShow = 0;
ButtonChanger bC;
void Update () {
buttonShow = ("bC.Change" + buttonNumber).toCode();
}

Something like this?
using System;
namespace ConsoleApplication1
{
enum ButtonChanger
{
Change1 = 1,
Change2 = 2,
Change3 = 3
}
class Program
{
static void Main(string[] args)
{
var changer = GetButtonChanger(2);
Console.WriteLine(changer);
Console.WriteLine((int)changer);
}
private static ButtonChanger GetButtonChanger(int i)
{
return (ButtonChanger)Enum.Parse(typeof(ButtonChanger), string.Format("Change{0}", i));
}
}
}

try using Dictionary<>. It will allow you to have key value pair. so your key would be bC.Change and you can retrive key using Key() method
eg
Dictionary<string, int> data = new Dictionary<string, int>();
data.Add("Change1", 123);
data.Add("Change2", 456);
foreach (string key in data.Keys)
{
Console.WriteLine(key);
}

I am not sure if I understand you right but given your title ... into commands I assume you are looking for a generic way to execute the methods in ButtonChanger.
If your ButtonChanger class is of type Component or GameObject you can use the SendMessage method:
MyClass.cs
const string ButtonShowPrefix = "Change";
ButtonChanger bC;
void Update () {
bC.SendMessage (ButtonShowPrefix + buttonNumber, SendMessageOptions.DontRequireReceiver);
}
ButtonChanger.cs
void Change1 () {
// do stuff for button 1
}
void Change2 () {
// do stuff for button 2
}
Note that it is possible to pass a parameter to the called method but there is no way to return a value. So if you need state information you have to work around this by using a public member in ButtonChanger.
As SendMessage is considered as somewhat expensive you should avoid unnecessary calls in case that no action has to be taken.
If things are getting more complex I would suggest combining this with gulshanm01 approach of using a dictionary for mapping identifiers to methods.

Related

C# Command parser

im currently expanding my knowledge a little, and wanted to Create a little game for myself.
The Structure is as Following:
Programm.cs creates an instance of Gamecontroller. This Gamecontroller is the lowest level i want to Access. It will create instaces of the Views, and from classes like config.
I want to implement an debug Console with Command Input. These Commands should always start at the Gamecontroller level, and should be able to interact with kinda everything i could do with C# code.
So i want to access the Objects, Member and methods withing Gamecontroller, or Within any nested object.
Currently i cant get to the Properties of an Child, because _member returns an "Type" which gets parsed to RuntimeProperty instead of the Class
Example on Parsing:
"objPlayer.name" > "GameController.objPlayer.name"
"objConfig.someSetting = 10" > "GameController.objConfig.someSetting=10"
"objConfig.functionCall()" > "GameController.objConfig.functionCall()"
"objConfig.objPlayer.setName("someName")" > "GameController.objConfig.objPlayer.setName("someName")"
"objPlayer.name" > "GameController.objPlayer.name"
this is what i got so far:
private void parseComamnd(string Command)
{
var actions = Command.Split('.');
var start = this.GetType();
var last = actions[actions.Length - 1];
foreach (var action in actions)
{
if (action.Contains("(") && action.Contains(")"))
{
_exec(start, action);
}
else
{
start = _member(start, action);
}
}
}
private Type _member(Type pHandle, string pStrMember)
{
return pHandle.GetProperty(pStrMember).GetType();
}
private void _exec(Type pHandle, string pStrFunction)
{
var Regex = new Regex(#"\(|,|\)");
var FunctionParams = Regex.Split(pStrFunction);
var FunctionName = FunctionParams[0];
FunctionParams[0] = "";
FunctionParams = FunctionParams.Where(val => val != "").ToArray();
pHandle.GetMethod(FunctionName).Invoke(FunctionName, FunctionParams);
}
If I understood right, you want to match some string commands with actions you want to perform. In this case you could use Dictionary as a storage for string-delgate couples to match your string commands to actions you want to perform. As an advantage of this approach, you can change matched couples during program runtime as you wish
class SomeClass
{
delegate void OperationDelegate(string value);
IDictionary<string, OperationDelegate> Operations = new Dictionary<string, OperationDelegate>();
public SomeClass()
{
Operations.Add("objPlayer.name", SetName);
Operations.Add("objConfig.someSetting", SetSetting);
}
public void HandleNewValue(string command, string value)
{
try
{
if (Operations.ContainsKey(command))
Operations[command](value);
}
catch (Exception e)
{
Logger.Error(e);
}
}
private void SetName(string value)
{
// Some logic there
}
private void SetSetting(string value)
{
// Some logic there
}
}

How to add a value to a key(object) in a dictionary if object has same name (C#)

So, I have a dictionary called Potions. I need to check if a key in potions has the same name as an object passed as an argument. Now I'm able to do that but I can't figure out how to add a value to that particular key if the item object and the key have the same name. This code works fine for the first instance of an object. But when I add another instance object with the same name as a key, I get a key not found exception. I understand that the 2 objects wont be the same.How can I extract the object reference inside the dictionary? Or is there another way?
public static void addItem(Potion item)
{
if (Potions.Count >0)
{
foreach(KeyValuePair<Potion,int> pair in Potions)
{
if (pair.Key.itemName == item.itemName)
{
containsItem = true;
}
}
if (containsItem)
{
Potions[item] += 1;
Debug.Log (Potions[item]);
containsItem = false;
}
else
{
Potions.Add(item,1);
}
}
else
{
Potions.Add (item,1);
}
foreach(KeyValuePair<Potion,int> pair in Potions)
{
Debug.Log (pair.Key.itemName + " : " + pair.Value);
}
}
I would actually offer an alternative implementation.
enum Potion
{
Health,
Mana
}
class PotionBag
{
readonly int[] _potions = new int[Enum.GetValues(typeof(Potion)).Length];
public void Add(Potion potion)
{
_potions[(int)potion]++;
}
public void Use(Potion potion)
{
if (GetCount(potion) == 0)
throw new InvalidOperationException();
_potions[(int)potion]--;
}
public int GetCount(Potion potion)
{
return _potions[(int)potion];
}
}
You can override Equals and GetHashCode, but that might have other implications. Instead, you can use an IEqualityComparer when you create the dictionary, like so:
class Potion {
public string Name;
public int Color;
}
class PotionNameEqualityComparer : IEqualityComparer<Potion> {
public bool Equals(Potion p1, Potion p2) {
return p1.Name.Equals(p2.Name);
}
public int GetHashCode(Potion p1) {
return p1.Name.GetHashCode();
}
}
void Main() {
var d = new Dictionary<Potion, int>(new PotionNameEqualityComparer());
var p1 = new Potion() { Name = "Health", Color = 1 };
var p2 = new Potion() { Name = "Health", Color = 2 };
d.Add(p1, 1);
d[p2]++; // works, and now you have two health potions.
// Of course, the actual instance in the dictionary is p1;
// p2 is not stored in the dictionary.
}
You're using Potion as the key, but according to your code, what matters to you is itemName. So, I'd recommend you to change your dictionary to <string, int>. Also, as commented, when using a custom class it's recommend to override Equals and GetHashCode.
Your code could be something like this:
public static void addItem(Potion item)
{
if(Potions.ContainsKey(item.itemName))
Potions[item.itemName] += 1;
else
Potions.Add (item.itemName,1);
foreach(KeyValuePair<string,int> pair in Potions)
{
Console.WriteLine(pair.Key + " : " + pair.Value);
}
}
That wont work since you're using the item that you're adding as a key, and it's not the same object.
Why not save the key in a placeholder and then look for it, after the loop?
Potion key = null;
foreach(KeyValuePair<Potion,int> pair in Potions)
{
if (pair.Key.itemName == item.itemName)
{
key = pair.Key
}
}
if(key != null):
Potions[key] += 1

how to store types as variables and use them in parameters' type?

class constType
{
public static const Type messageType = typeof(int); // HOW TO DO THIS? 1st mark
public string[] GetArraySomehow()
{
return new string[sizeof(messageType)]; // HOW TO DO THIS? 2nd mark
}
}
class testTypeInClass
{
public void test(constType.messageType message) // HOW TO DO THIS? 3rd mark
{
}
}
Okay so this is really weird and strange I know but how can I do this?
1st mark: I have to store int's type as const variable and use it laterç
2nd mark: I have to get stored type's size (how many bytes does it equal?)
3rd mark: I have to use it as a parameter type.
Well Why I have to do this such thing:
I have to store a type (not so wide, just I know I'll use int8,16,32 etc)
and have to know what exactly bytes does it equal (1,2,4 etc..);
well first of all I have a method in one of my classes which uses switch statement and:
like this:
public string test (int messageIndex)
{
switch (messageIndex)
{
case 0:
return "etc.. etc..";
case 1231412:
return "whatever";
}
}
Firstly I had some method like this:
public int fixForSwitchStatement(byte[] messageIndex)
{
byte[] RValue = new byte[4];
for (int i = 0; i <= messageIndex.Length - 1; i++)
{
RValue[i] = messageIndex[i];
}
for (int i = messageIndex.Length; i <= 4 - messageIndex.Length - 1; i++)
{
RValue[i] = 0;
}
return BitConverter.ToInt32(RValue, 0);
}
I was passing byte or short to switch statement then I was converting to int (int was a specified type for me) and I wanted to make a redesign like this.
public string test (/* [what's the case limit? that I've determined?] */ messageIndex)
{
switch (messageIndex)
{
case 0:
return "etc.. etc..";
case 1231412:
return "whatever";
}
}
Because I don't want to use fixSwitch... method anymore. I just need a specified type for all of these concept.
Why I have to use fixSwitch instead of typecasting like (int)somethingByte?
Well in my one of classes there is a thing called communicationSize, its the messageIndex thing's maximum size in byte(s) that I have to declare. This is for my server-client project. There is a messageIndex thing being used as a request index what server and client requests from each other. And I'm limiting it with byte(s). For save some data space from connection.
// still is being written
I'm not sure what the goal is and the question has been edited in the meantime but heres some example code using generics that may help you further.
class constType<T> where T : struct
{
public T GetT()
{
return new T();
}
public string[] GetArraySomehow()
{
var len = Marshal.SizeOf(typeof(T));
return new string[len];
}
}
class testTypeInClass
{
public void test<T>(T message) where T : struct
{
}
}
class MyClass
{
void Test()
{
var constType = new constType<int>();
var typeInClass = new testTypeInClass();
var t = constType.GetT();
typeInClass.test(t);
}
}

Threading Parallel Invoke, Action

My code as below
public void DownloadConcurrent(Action<string> Methord)
{
Action<string>[] methordList = new Action<string>[Concurent_Downloads];
for (int i = 0; i < Concurent_Downloads; i++)
{
methordList[i] = Methord;
}
Parallel.Invoke(methordList);
}
Parallel.Invoke is giving error:
"cannot convert from 'System.Action<string>[]' to 'System.Action[]'"
The Method it is calling is
public void DownloadLinks(string Term)
{
}
check Parallel.ForEach like the following
static void Main(string[] args)
{
List<string> p = new List<string>() { "Test", "Test2", "Test3"};
Parallel.ForEach(p, Test);
}
public static void Test(string test)
{
Debug.WriteLine(test);
}
This should do the trick for you
HTH
Dominik
In your case it is easier if you use
Parallel.ForEach
over your string list instead of using
Parallel.Invoke
with additional parameter. Let me know if you want to stick to Parallel.Invoke.
Parallel.Invoke accepts Action array while your code is passing it an Action<string> array. What you can do is :
public void DownloadConcurrent(Action<string> Methord)
{
Action<string>[] methordList = new Action<string>[Concurent_Downloads];
var r = methordList.Select(a => (Action)(() => a("some_str"))).ToArray();
Parallel.Invoke(r);
}
You need to replace some_str with proper value for each action

c# program of Indexers

there is an error in this program.can anyone fix that?
Error is :TempRecord already defines a member called 'this' with the same parameters value
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication6
{
class TempRecord
{
// Array of temperature values
private float[] temps = new float[10] { 56.2F, 56.7F, 56.5F, 56.9F, 58.8F,
61.3F, 65.9F, 62.1F, 59.2F, 57.5F };
private int[] d= new int[10]{4,5,5,4,4,43,2,2,5,3};
// To enable client code to validate input
// when accessing your indexer.
//public int Length
//{
// get { return temps.Length; }
//}
// Indexer declaration.
// If index is out of range, the temps array will throw the exception.
public float this[int index]
{
get
{
return temps[index];
}
set
{
temps[index] = value;
}
}
public int this[int index]//error:TempRecord already defines a member called 'this' with the same parameters value
{
get
{
return d[index];
}
set
{
d[index] = value;
}
}
}
class Program
{
static void Main(string[] args)
{
TempRecord tempRecord = new TempRecord();
// Use the indexer's set accessor
tempRecord[3] = 58.3F;
tempRecord[5] = 60.1F;
// Use the indexer's get accessor
for (int i = 0; i < 10; i++)
{
System.Console.WriteLine("Element #{0} = {1}", i, tempRecord[i]);
}
Console.WriteLine(tempRecord[2]);
// Keep the console window open in debug mode.
System.Console.WriteLine("Press any key to exit.");
System.Console.ReadKey();
}
}
}
You have two members named this, that take the same parameters. That's not allowed in C# (or other .Net languages, as far as I'm aware).
You'd think you'd be able to do this if both members return different types, as yours do. But that would present the compiler with ambiguity. Which member would be called if you had code like this?
object x = tempRecord[3];
Make one or both indexers a method.
What you're trying to do is have 2 indexers with the same parameters and different return types. This is not legal in C#. You'll need to move at least one of them into a function
public int GetD(int index) {
return d[index];
}
public void SetD(int index, int value) {
d[index] = value;
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication6
{
class TempRecord
{
// Array of temperature values
private float[] temps = new float[10] { 56.2F, 56.7F, 56.5F, 56.9F, 58.8F, 61.3F, 65.9F, 62.1F, 59.2F, 57.5F }; private int[] d = new int[10] { 4, 5, 5, 4, 4, 43, 2, 2, 5, 3 };
public int Length //
{
get { return temps.Length; }
}
public float this[int index]
{
get { return temps[index]; }
set { temps[index] = value; }
}
}
class Program
{
static void Main(string[] args)
{
TempRecord tempRecord = new TempRecord();
tempRecord[3] = 58.3F;
tempRecord[5] = 60.1F;
for (int i = 0; i < 10; i++)
{
System.Console.WriteLine("Element #{0} = {1}", i, tempRecord[i]);
}
Console.WriteLine(tempRecord[2]);
System.Console.WriteLine("Press any key to exit.");
System.Console.ReadKey();
}
}
}
If you are trying some concept similar to overloading of functions, I'd like to say it never works with just a change in return type. Similar is the case of data members, where you have tried to use this with the same arguments but different return types.
The best method would be however (even for readability sake) making separate functions for the exclusive events that are being performed above.
I deleted the second data member above, replace it with the something like the foll. I think you better use temprecord.d[index Value] to access & use the member d from main.
public int d[int index]
{
get
{
return d[index];
}
set
{
d[index] = value;
}
}

Categories