I want control a other device with a C# program, this device have something like registers for read and write. So I searching something to enter all register numbers to get a better human readable code and to have central config place. All the registers using a uint value.
I searching something like this:
public enum EISCJoin : uint
{
Read_Connect = 1,
Read_Temp = 2,
Read_Switch = 3,
Write_Connect = 1,
Write_Temp = 2,
Write_Switch = 3,
}
switch (args.Sig.Number) //uint value
{
case (uint)EISC.Read_Connect:
{
args.SendValue[(uint)Write_Connect] = 1;
...
break;
}
case (uint)EISC.Read_Temp:
{
args.SendValue[(uint)Write_Temp] = 1;
...
break;
}
case (uint)EISC.Read_Switch:
{
args.SendValue[(uint)Write_Switch] = 1;
...
break;
}
}
My problem is that I don't want cast the ENUM value thousands of times in my source code and what I know is that a implicit conversation is not possible with enum.
Have someone a good idea to create a constant list of uint values?
you need to cast the number instead:
switch (args.Sig.Number)
to
switch ((EISCJoin)args.Sig.Number)
The other way is to use a static class and constant uints:
static public class EISCJoin
{
public const uint Read_Connect = 1;
public const uint Read_Temp = 2;
// and so on
}
I must work with a framework of the manufacturer and have no access to all the classes, it is not a option to modify all classes to the enum.
I using a value the most time only 1-2 times, so the most time I cast the value for 1 time use.
It looks like I must use the static class with the const uint variables.
Thanks for your help
Related
Skip to the third paragraph for the question.
Context: I'm creating a 2D spaceship game, and one of the game mechanics is routing power to the 7 different parts of the ship to suit the current situation you're in. There are presets that you can switch to at any time, called power configurations. I have the power configurations stored in 3 different arrays, like so:
int[] powerConfiguration1 = new int[7] {10,10,10,10,20,20,20};
int[] powerConfiguration2 = new int[7] {20,20,20,10,10,10,10};
int[] powerConfiguration3 = new int[7] {10,20,10,20,10,20,10};
When you switch configurations, it calls a method for doing so. The method makes some calculations to determine how long it will take to switch configurations. However, instead of making a switch statement and copy/pasting the code several times in the case of the player switching to any of the three configurations, I want to use PropertyInfo in System.Reflections to choose which property I need to pull values from.
Question: The problem is that I don't know how to get an item from an array. Here is what I have so far, where I'm attempting to determine how much power will need to be rerouted in total and adding it all to a variable. 0 is the index in the configuration at which I have decided to store the shield power. powerToShields is the current power being routed to the shields.
void switchConfiguration(int number) {
PropertyInfo powerConfiguration = GetType().GetProperty("powerConfiguration" + number);
int powerToReroute = 0;
powerToReroute += Mathf.Abs(powerToShields - powerConfiguration[0]);
Could someone please explain what I'm doing wrong and/or show me how to fix it? Or, is there a better way to do this?
EDIT 1: This is coded in C# (Unity).
Side thought
I guess my first question is why not store the arrays in a list. So, instead of powerConfiguration1, powerConfiguration2, powerConfiguration3, why not just store a list of int[], so
List<int[]> powerConfigurationList = new List<int[]>;
powerConfigurationList.Add(new int[7] {10,10,10,10,20,20,20});
powerConfigurationList.Add(new int[7] {20,20,20,10,10,10,10});
powerConfigurationList.Add(new int[7] {10,20,10,20,10,20,10});
That way you can get the item via:
powerToReroute = (powerConfigurationList[number])[0]
Answer to your question
However, assuming that there is some good reason that you can't, and in order to answer your exact question, do the following:
...
PropertyInfo powerConfiguration = GetType().GetProperty("powerConfiguration" + number); //this line is taken from your example above
//then you need to do something like the below
var value = (int[])powerConfiguration.GetValue(instanceThatHasTheProperty);
int powerToReroute = 0;
powerToReroute += Mathf.Abs(powerToShields - value[0]);
From your code snippet, I see you have GetType().GetProperty("powerConfiguration" + number);. I'm not sure what the actual instance is that your getting that type from. So you need to replace instanceThatHasTheProperty in my above snippet, by whatever instance you're trying to get the property's value from.
The thing that is immediately obvious to me is that the code is unnecessarily obfuscated and seems an awful lot like an X-Y problem. Using jagged arrays and reflection seems like a whole lot of work to end-around object oriented programming. My recommendation would be to create a class to store your power configurations, store multiple power configurations in a list, and then select the configuration from the list.
Sample Class for Power Configurations
public class PowerConfiguration
{
public int ID { get; set; }
public string Name { get; set; }
public int Shields { get; set; }
public int Weapons { get; set; }
public int LifeSupport { get; set; }
public int Propulsion { get; set; }
}
Inserting and Accessing your Power Configurations
public class DoStuff
{
public void LoadPowerConfiguration()
{
// Create a List to store configurations
List<PowerConfiguration> allPowerConfigurations = new List<PowerConfiguration>();
// Add some mock data to the list
allPowerConfigurations.Add(new PowerConfiguration()
{
ID = 0,
Name = "Balanced Combat",
Shields = 30,
Weapons = 30,
LifeSupport = 20,
Propulsion = 20
});
allPowerConfigurations.Add(new PowerConfiguration()
{
ID = 1,
Name = "Offensive",
Shields = 20,
Weapons = 50,
LifeSupport = 10,
Propulsion = 20
});
// Figure out which ID you what (eg. from the user pressing '0')
int selectedConfigurationID = 0;
// Get the configuration from the list
PowerConfiguration selectedConfiguration =
allPowerConfigurations.FirstOrDefault(p => p.ID == selectedConfigurationID);
// Now perform your operations against the PowerConfiguration object's properties
int powerToShields = 100;
int powerToReroute = 0;
powerToReroute += Math.Abs(powerToShields - selectedConfiguration.Shields);
}
}
public enum Levels
{
LevelState1 = 0,
LevelState2 = 1,
LevelState3 = 2
}
private Levels currentLevel;
public void ChooseLevel(Levels levelstate)
{
switch (levelstate)
{
case Levels.LevelState1:
currentLevel = Levels.LevelState1;
...
break;
case Levels.LevelState2:
currentLevel = Levels.LevelState2;
...
break;
case Levels.LevelState3:
currentLevel = Levels.LevelState3;
...
break;
}
}
//The variable CurrentLevel is an integer
ChooseLevel(Levels."LevelState"+game1.CurrentLevel.ToString());
I always get this error message in the last line:
Identifier expected
What should I change? I don't know how to fix this problem.
Either wrap this in a try/catch:
Levels level = (Levels)Enum.Parse(typeof(Levels),
"LevelState" + game1.CurrentLevel.ToString());
ChooseLevel(level);
Or use Enum.TryParse()
I feel that you are overcomplicating things. You can do this much simpler in a way similar to this:
public enum Levels
{
LevelState1 = 1,
LevelState2 = 2,
LevelState3 = 3
}
private Levels currentLevel;
public void ChooseLevel(int state)
{
currentLevel = (Levels)state; // casting to enum from int
// process level or whatever here
}
//The variable CurrentLevel is an integer
ChooseLevel(game1.CurrentLevel);
Since your CurrentLevel variable is an integer, you can easily cast it to your enum by binding level states to actual integer values within the level range. So instead of starting at 0 in your enum, you start at the first level value (which in your case is 1, no?).
Hope this helps.
ChooseLevel expectes enum argument, whereas you're using a mixture of enum and string, you'll have to parse it:
Levels game1Level = (Levels)Enum.Parse(typeof(Levels), "LevelState" + game1.CurrentLevel);
ChooseLevel(game1Level);
You can also use Enum.TryParse
i have the following array :
int[] myArray = {21,21,364,658,87};
and a reference to the second element like so:
int rr = myArray[1];
i want something like :
rr = 500
Console.writeLine(myArray[1]);// ---> should print 500 !
i hope you guys got my idea , i can do this easily in python like the example above.
so
how to do this in C#
my solution would probably be create property with arr[1] as its backing property
something like:
public int rr
{
set{ arr[1] = value;}
get{ return arr[1];}
}
and than rr=500; will be the same as arr[1]=500;
You could use something like this:
public static class ArrayExtensions
{
public static Action<int> CreateSetter(this int[] array, int index)
{
return (value) => array[index] = value;
}
}
[TestFixture]
public class ArrayTest
{
[Test]
public void Test()
{
int[] myArray = {21,21,364,658,87};
Action<int> rr = myArray.CreateSetter(1);
rr(500);
Assert.AreEqual(500, myArray[1]);
}
}
When you do this:
int[] myArray = {21,21,364,658,87};
int rr = myArray[1];
rr = 500;
You will only overwrite the value in rr, there is no way for you to get the actual memory address of an arrays inner elements, and thereby updating it.
My answer must therefore be:
myArray[1] = 500;
I'm trying to understand what you're trying to do, if you want to encapsulate your change in a function you could pass the reference on this way, but it's all about what you want to do with it:
public void Proc()
{
var ints = new [] { 1, 2, 3, 4 };
FunctionChangingByReference(ref ints[1]);
}
public void FunctionChangingByReference(ref int x)
{
x = 500;
}
In C# there are no pointers, only references.
(I'm lying a bit, you could use pointers if you create a unsafe context, but we don't do that in C#, and neither should you. When we code C++ we do, but that's C++, and we do it at a cost, we make the code a bit more fragile and error prone. When I code C# I try to optimize the code on a higher level than memory address shuffling. If you really need to optimize on that level you should write the code in C++ and import that code as a dll, then you have a good separation of concern, and don't forget to test drive the development!)
Simply myArray[1] = 500! You could use a property as Nahum Litvin has suggested if you specifically want a reference to a specific integer within the array.
#des answer has awaken my interest. So I tried his solution and it works as expected:
int[] numbers = new[] { 1, 2, 3 };
fixed (int* number = &numbers[0])
{
*number = 10;
}
Console.WriteLine(String.Join(", ", numbers)); // Outputs "10, 2, 3"
You have to compile it with the /unsafe option.
I hope you see that this may bring some problems.
Therefore I don't recommend this solution.
What you want is a basically pointer to a variable.
It's hard to explain the difference between "value type" (like int or struct), a reference and a pointer. I can only recommend learning C.
Here's solution that works, although it may need a lot of changes to your code.
//a class that will hold an int inside
public class myIntWrapper
{
//this is the value wrapper holds
public int theValue;
//constructor taking the value
public myIntWrapper(int argument)
{
theValue = argument;
}
//operator to convert an int into brand-new myIntWrapper class
public static implicit operator myIntWrapper(int argument)
{
return new myIntWrapper(argument);
}
//operator to convert a myIntWrapper class into an int
public static implicit operator int(myIntWrapper wrapper)
{
return wrapper.theValue;
}
}
now you can write:
//create an array -
//setting values to every item in array works
//thanks to operator myIntWrapper(int argument)
myIntWrapper[] myArray = new myIntWrapper[5]{1,2,3,4,5};
//now take a "reference"
myIntWrapper rr = myArray[1];
//change the value
rr.theValue = 500;
//from now on myArray[1].theValue is 500;
//thanks to operator int(myIntWrapper wrapper)
//you can write:
int ss = rr;//it works!
please remember to never do:
rr = 600;
because this will actually create brand new myIntWrapper, that's not "connected" anywhere.
So remember:
rr.theValue = 500;//this changes the value somewhere
rr = myArray[3];//this changes where rr is "pointing" to
Yes, it's quite complicated but I doubt it can be done any simpler without unsafe code. I'm sorry for not explaining it more. I'll answer to all questions in comments.
in java its possible to do something like this
class {
final int x = Random.randomInt();
final int y = Random.randomInt();
}
...
switch (intVariable)
{
case x: break;
case y: break;
}
as long as generateInt is final, this compiles.
is there an equivalent in C#?
edit: you might ask why i dont use concrete values or enums, but i have my reasons why the values are be random. ;)
with const you can't do that, it has to be a compile time constant.
You may use readonly, something like:
public class yourClass
{
public readonly int x = generateInt();
public static int generateInt()
{
return DateTime.Now.Millisecond; // or any other method getSomeInt();
}
}
EDIT:
Since the question is now edited and asks with reference to case expression in switch statement. You can't specify a variable or readonly in the case statement, it has to be constant expression/compile time constant.
From MSDN - Switch
Each case label specifies a constant value.
You may use if...else for your scenario.
I am trying to cast from an int to an enum, unsuccessfully, as follows:
ENUM
public enum ePriceType{
Fixed = 1,
Variable = 2
}
CAST
public int priceTypeA = 2;
public ePriceType priceTypeB = (ePriceType)priceTypeA;
Code runs fine, but for some reason when you check the value of priceTypeB it still shows an int and not an ePriceType which causes an error further down the code.
Can anyone help?
UPDATE
In truth, this problem is a whole lot more complex involving the client side of a web service. I tried to simplify it as above but clearly didnt quite work and Im not sure how simplest to explain the full problem :( Thanks for your answers anyway
when you check the value of priceTypeB it still shows an int
No idea how you are checking this value and where why you are seeing an int but the following check works perfectly fine:
public enum ePriceType
{
Fixed = 1,
Variable = 2
}
class Program
{
static void Main()
{
int priceTypeA = 2;
ePriceType priceTypeB = (ePriceType)priceTypeA;
if (priceTypeB == ePriceType.Variable)
{
Console.WriteLine("Variable");
}
}
}
Try this:
public class EnumProvider
{
public enum ePriceType{
Fixed = 1,
Variable = 2
}
var a = Enum.GetName(typeof(EnumProvider.ePriceType), 1);
here a would be "Fixed"