Faster way to compare enums? - c#

I'm looking for a better way to compare enums. Currently, I have an enum with 3 different possible values:
public enum Elements { fire, water, earth };
However, an example of a function where something happens when two Elements collide:
Public Void ElementCollisionExample(Elements element1, Elements element2){
if (element1 == Elements.fire){
if (element2 == Elements.fire){
//Do stuff
} else if (element2 == Elements.water){
// Do stuff
} else {
// Do stuff
}
} else if (element2 == Elements.water){...etc...}
}
And that is only for the Fire Element!
I've searched a while, and looked on similar SO questions, but I'm not sure how to formulate the problem. All I've found are questions such as "Is '==' or '.Equals()' faster to compare Enums???", which is entirely different.
Is there an easy way to do this? I already have these conditions being handled in a separate Manager, but it still irritates me.
EDIT:
A combination of elements always has the same outcome. So Fire + Water = X, and Water + Fire = X as well.

It will be cleaner code with C# switch conditions introduced in C# 7.0.
public void ElementCollisionExample(Elements element1, Elements element2)
{
// Do nothing on equal elements
if (element1 == element2) return;
switch (element1)
{
case Elements.fire when element2 == Elements.water:
case Elements.water when element2 == Elements.fire:
// Do stuff
break;
case Elements.fire when element2 == Elements.earth:
case Elements.earth when element2 == Elements.fire:
// Do stuff
break;
case Elements.water when element2 == Elements.earth:
case Elements.earth when element2 == Elements.water:
// Do stuff
break;
}
}
Updated: Order of element1 and element2 does not matter. Also ignoring equal elements.

One option is to have a dictionary of actions you can invoke. For example:
public class ElementActionFactory
{
// Somewhere to keep our actions, using tuple to pair up elements
private Dictionary<(Elements, Elements), Action> _elementActions;
public ElementActionFactory()
{
// Initialise the action dictionary
_elementActions = new Dictionary<(Elements, Elements), Action>
{
{(Elements.Fire, Elements.Fire), FireAndFire},
{(Elements.Fire, Elements.Water), FireAndWater},
{(Elements.Fire, Elements.Earth), FireAndEarth},
// etc.
};
}
public void Invoke(Elements element1, Elements element2)
{
// Try to get the action, and if we don't find it...
if (!_elementActions.TryGetValue((element1, element2), out var action))
{
// reverse the arguments and try again - this assumes the order is not important
if (!_elementActions.TryGetValue((element2, element1), out action))
{
return; //No action was found
}
}
// Actually run the method now
action.Invoke();
}
public void FireAndFire()
{
Console.WriteLine("Fire And Fire");
}
public void FireAndWater()
{
Console.WriteLine("Fire And Water");
}
public void FireAndEarth()
{
Console.WriteLine("Fire And Earth");
}
}
And to use it, it's simply:
var elementActionFactory = new ElementActionFactory();
var element1 = Elements.Fire;
var element2 = Elements.Water;
elementActionFactory.Invoke(element1, element2);

Assuming that the order in which the elements are combined does not matter, you could treat the enumeration as a bit field, that is, a set of flags - so you can combine them allowing you to have a simple switch. For example:
[Flags]
public enum Elements
{
none = 0b0000_0000_0000,
fire = 0b0000_0000_0001,
water = 0b0000_0000_0010,
earth = 0b0000_0000_0100
};
public void ElementCollisionExample(Elements element1, Elements element2)
{
switch (element1 | element2)
{
case Elements.fire | Elements.water:
Console.WriteLine("The fire is extinguished");
break;
case Elements.earth | Elements.fire:
Console.WriteLine("The earth goes black");
break;
}
}

For Cleaner Code i suggest using complex switch ...
Elements x, y;
switch (x)
{
case Elements.fire:
switch (y)
{
case Elements.fire:
break;
case Elements.water:
break;
case Elements.earth:
break;
}
break;
case Elements.water:
switch (y)
{
case Elements.fire:
break;
case Elements.water:
break;
case Elements.earth:
break;
}
break;
case Elements.earth:
switch (y)
{
case Elements.fire:
break;
case Elements.water:
break;
case Elements.earth:
break;
}
break;
}

With tuples, you can avoid the nested ifs:
public void ElementCollisionExample(Elements element1, Elements element2)
{
Tuple<Elements,Elements> elements = Tuple.Create(element1,element2);
if(elements.Equals(Tuple.Create(Elements.fire, Elements.earth))
{
//do something
}
else if(elements.Equals(Tuple.Create(Elements.fire, Elements.water))
{
// do something
}
// and so on
}
You can simplify it more if you create a separate function:
public void ElementCollisionExample(Elements element1, Elements element2)
{
Tuple<Elements,Elements> elements = Tuple.Create(element1,element2);
if(CompareElements(elements, Elements.fire, Elements.earth))
{
//do something
}
else if(CompareElements(elements, Elements.fire, Elements.water))
{
// do something
}
// and so on
}
private bool CompareElements(Tuple<Elements,Elements> actual, Elements expected1, Elements expected2)
{
return actual.Equals(Tuple.Create(expected1, expected2));
}

Related

How can I optimize this code for better readability?

I'm not a good programmer, for my bodypart-based collision detection in a game in unity I'm making I've ended up with a switch that looks like this despite my best attempts to simplify and shorten it:
public void GetCollision(Collision2D col) {
if (attackType == -1) {
if (col.gameObject.name == "Sword") {
hitboxDisable();
} else if (col.gameObject.name == "Player") {
pim.PlayerDamage(5);
}
}
if (col.gameObject.name == "Player_Body") {
switch (attackType) {
case -2: {
pim.PlayerDamage(5);
}
break;
case 0:
if (!pa.playerIsDodging) {
pim.PlayerDamage(5);
} else {
pa.dodgeOnCooldown = false;
pa.resetDodgeRoutine();
hitboxDisable();
}
break;
case 1:
if (!swordSrc.isDefendingLegRight) {
pim.PlayerDamage(5);
} else {
weaponBlocked = true;
}
break;
case 2:
if (!swordSrc.isDefendingArmRight) {
pim.PlayerDamage(5);
} else {
weaponBlocked = true;
}
break;
case 3:
if (!swordSrc.isDefendingHeadRight) {
pim.PlayerDamage(5);
} else {
weaponBlocked = true;
}
break;
case 4:
if (!swordSrc.isDefendingLegLeft) {
pim.PlayerDamage(5);
} else {
weaponBlocked = true;
}
break;
case 5:
if (!swordSrc.isDefendingArmLeft) {
pim.PlayerDamage(5);
} else {
weaponBlocked = true;
}
break;
case 6:
if (!swordSrc.isDefendingHeadLeft) {
pim.PlayerDamage(5);
} else {
weaponBlocked = true;
}
break;
}
if (weaponBlocked == true) {
hitboxDisable();
RandomOpening();
ApplyForce(testvar1, testvar2);
weaponBlocked = false;
}
}
}
How can this be shortened and optimized for better readability? I'm new to C# and what little of my programming has been in C, I know there are a lot of ways to improve readability in C# I just don't know when/how to apply them. Suggestions would be much appreciated, I'm willing to try and learn anything, I want to try and avoid ending up with big switch statements like this if possible. Even just a suggestion what to apply here would be really appreciated, an example would be great.
I made the attackTypes into integers, they could have been strings but I chose not to because to my understanding strings take longer to compare. The attackType value specifies in the switch where the attack is targeting and if/how to block it, then if it was blocked.
Case 1-6 seem very similar. You can make use of a local function
public void GetCollision(Collision2D col) {
// this is a local function which you can only use inside this function
// which can be useful if you have a short repeating pattern inside the function
// and don't need it anywhere else
void _handleHit(bool isDefending) {
if (isDefending) {
pim.PlayerDamage(5);
} else {
weaponBlocked = true;
}
}
[...] // your code
switch (attackType) {
[...] // your code
case 1: _handleHit(!swordSrc.isDefendingLegRight); break;
case 2: _handleHit(!swordSrc.isDefendingArmRight); break;
case 3: _handleHit(!swordSrc.isDefendingHeadRight); break;
...
}
}
You could also take a look at C# enums and replace attackType with a readable version.
// Declaring the enum
public enum AttackType { Direct, LeftArm, ... }
// Then in a switch case you can do:
switch (attackType) {
case AttackType.Direct: ...
case AttackType.LeftArm: ...
}
One thing would be to create a enum to describe the bodyparts, i.e.
public enum Bodypart{
None,
Head,
LeftArm,
RightArm,
LeftLeg,
RightLeg,
}
This could allow you to replace all the isDefendingArmLeft properties with a DefendingBodyPart. Likewise your attacks could be described by a combination of attack type and bodypart, this also removes the need to guess what attackType = -2 means:
public enum Attacktype{
Magic,
Sword,
Bodypart,
}
So that you can check first if the attacker attacks a specific body-part, and if the target is defending that specific body-part. If you want to allow defense or attack of multiple bodyparts you could use a [Flags] enum with one bit per bodypart.

How to store outcome of switch statement into an object in c#

Is it possible to create an object that stores the outcome of the switch statement in c#? Because my end goal is to compare the object in an if statement, and if that's true then it will print a writeline.
switch (results)
{
case 1:
checkingWriter.WriteLine("text");
break;
case 0:
checkingWriter.WriteLine("text");
error_Found = true;
break;
case -1:
checkingWriter.WriteLine("text");
error_Found = true;
break;
case -2:
checkingWriter.WriteLine("text");
error_Found = true;
break;
case -3:
checkingWriter.WriteLine("text");
error_Found = true;
break;
}
You are mixing both side effects and the computation of a value; this is a bad code smell and you might consider separating that logic.
To address your specific question: at this time there is no easy way to get a value computed by a particular switch case section out of the switch. However, this feature has been proposed for C# 8.0, so it seems likely that you'll get some version of this. See the link below for the proposal:
https://neelbhatt.com/2018/05/19/c-8-0-expected-features-part-iii-switch-statments/
Yes, something like (but very basic since we do not have any details):
var objectToCheck = ...; // Some initialized value or null
switch(...)
{
case ...:
objectToCheck = ...
break;
case ...:
objectToCheck = ...
break;
...
default:
Error handling
}
if (objectToCheck ==/.Equals(...) ) // Check object
create variable before switch statement begins, store the switch case result in variable. After switch ends, use the variable in the if condition.
var result = null;
switch (caseSwitch)
{
case 1:
result = fn1();
break;
case 2:
result = fn2();
break;
default:
Console.WriteLine("Default case");
break;
}
if(result == 'your condition')
do something
There are not enough details but may this works, or give you a new idea:
public class Foo
{
public static bool operator !=(Foo foo1, int results){
return results <= 0;
}
public static bool operator ==(Foo foo1, int results){
switch(results)
{
case 1:
Console.WriteLine("All gones good");
return false;
case 0:
Console.WriteLine("Nothing happend");
break;
case -1:
Console.WriteLine("Error 183");
break;
case -2:
Console.WriteLine("Fatal Error");
break;
case -3:
Console.WriteLine("The user doesn't exists");
break;
default:
return false;
}
return true;
}
}
And when you use it:
public static void Main()
{
Foo foo = new Foo();
int results = 0;
// makes some logic that fills results
if(foo == results){
Console.WriteLine("Do Something Custom Here");
}
results = -1;
if(foo == results){
Console.WriteLine("Do Another Something Custom Here");
}
}
It will give you in console something like this:
//Nothing happend
//Do Something Custom Here
//Error 183
//Do Another Something Custom Here

Get column index as constant value

Currently i am having code like this inside dataGridView1_CellValidating event:
if(e.ColumnIndex == dataGridView1.Columns["FIRST"].Index)
{
// Some code
}
else if(e.ColumnIndex == dataGridView1.Columns["Second"].Index)
{
// Some code
}
else if(e.ColumnIndex == dataGridView1.Columns["Third"].Index)
{
// Some code
}
And it is like this because i cannot use it in switch statement like:
switch(e.ColumnIndex)
{
case dataGridView.Columns["First"].Index:
break;
case dataGridView.Columns["Second"].Index:
break;
case dataGridView.Columns["Third"].Index:
break;
}
returns me error on case line Expecting constant value.
So how can i make this work?
The switch statement is complaining because the “case” portion of the statement “requires” a “CONSTANT” value. The statement dataGridView.Columns["First"].Index will always return the same value… unless you move the column… which you can do. This is why the compiler is going to look at the retuned value from dataGridView.Columns["First"].Index as NOT a “constant”.
This makes sense in the fact that the “column index” for the column named “First” could be at ANY column index in the grid… Hence the error.
A possible solution is to grab the current columns “Name” string value then switch off the column “Name” like below.
string columnName = dataGridView.Columns[e.ColumnIndex].Name;
switch (columnName) {
case "First":
MessageBox.Show("Cell Validated is in 'FIRST' column");
break;
case "Second":
MessageBox.Show("Cell Validated is in 'Second' column");
break;
case "Third":
MessageBox.Show("Cell Validated is in 'Third' column");
break;
}
If you really want to use switch you can make use of pattern matching in switch case
PS: For C# 7.0 or above
switch(e.ColumnIndex)
{
case var _ when (dataGridView.Columns["First"].Index == e.ColumnIndex):
break;
case var _ when (dataGridView.Columns["Second"].Index == e.ColumnIndex):
break;
case var _ when (dataGridView.Columns["Third"].Index == e.ColumnIndex):
break;
}
Maybe, you first make constant values and assign dataGridView.Columns["First"].Index to it.
For example:
int a = {given index}
const int IndexOfFirstCol = dataGridView.Columns["First"].Index;
const int IndexOfSecCol = dataGridView.Columns["Second"].Index;
then,
switch(a)
{
case IndexOfFirstCol:
//do smth
break;
case IndexOfSecCol:
//do smth
break;
}
If you cannot use pattern matching from C# 7.0, there is also another way by using dictonaries where your keys are functions checking the conditions (cases) and the values are the actions you want to perform. For your code it would look like:
private void dataGridView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
var caseDictionary = new Dictionary<Func<bool>, Action>()
{
{ () => (e.ColumnIndex == dataGridView1.Columns["First"].Index), () => { MessageBox.Show("First");}},
{ () => (e.ColumnIndex == dataGridView1.Columns["Second"].Index), () => { MessageBox.Show("Second");}},
{ () => (e.ColumnIndex == dataGridView1.Columns["Third"].Index), () => { MessageBox.Show("Third");}}
};
caseDictionary.Where(caseRecord => caseRecord.Key()).Select(action => action.Value).FirstOrDefault()?.Invoke();
}
You could of course declare the Dictionary in your constructor and just call it in the CellValidating event.
I would have another approach, using a Dictionnary (from the namespace System.Collections.Generic) of methods built in such way
The key is the index of the column in the datagridview ("First", "Second" ...)
The value is a Delegate to the method to do (what replaces your // some code in each if/else if
In example :
/*
* This example is written for console application, that can be tested easily.
* The logic can be rewritten for WinForm
*/
static void TheFirstCase()
{
//This should be replaced by the differents actions you want to do
Console.WriteLine("first case");
}
static void TheSecondtCase()
{
Console.WriteLine("second case");
}
static void TheThirdCase()
{
Console.WriteLine("third case");
}
static void Main(string[] args)
{
Dictionary<string, Delegate> MyDic = new Dictionary<string, Delegate>
{
//If you need parameters in the TheFirstCase(), use new Action<TypeOfTheFirstParam, TypeOfTheSecondParam, ...>(TheFirstCase)
//If your Method needs to return something, use Func instead of Action
{ "First", new Action(TheFirstCase) },
{ "Second", new Action(TheSecondtCase) },
{ "Third", new Action(TheThirdCase) }
};
// in your question, this is e.ColumnIndex
var ValueInColIndex = 42;
// in your question, this is dataGridView.Columns
var DataGridViewDatas = new Dictionary<string, int>
{
{ "First", 0 },
{ "Second", 42 },
{ "Third", 69 }
};
foreach (var MyAction in MyDic)
{
if (DataGridViewDatas[MyAction.Key] == ValueInColIndex)
{
MyAction.Value.DynamicInvoke();
}
}
}
Outputs :
second case

C# Chart - data is repeated

I have the following Data (from the database):
These are stored in objects that are stored in a list:
for creating the chart series i have created the following function:
public void CreateSeries(DateTime seriesTime)
{
while (true)
{
if (seriesTime.Date > _stopDate.Date) return;
foreach (var data in _datalist)
{
var currentData = (Email)data;
String xLabel;
switch (_timeType)
{
case DateUtils.TimeType.Weeks:
xLabel = seriesTime.Date.ToString("dd");
break;
case DateUtils.TimeType.Months:
xLabel = seriesTime.Date.ToString("MM");
break;
case DateUtils.TimeType.Years:
xLabel = seriesTime.Date.ToString("yyyy");
break;
default:
xLabel = seriesTime.Date.ToString("dd");
break;
}
AddData(currentData, xLabel);
}
if (DateConverter.GetDaysBetween(seriesTime, _stopDate) >= 0)
{
seriesTime = AppendDays(seriesTime);
continue;
}
break;
}
}
protected DateTime AppendDays(DateTime initialDateTime)
{
switch (_timeType)
{
case DateUtils.TimeType.Weeks:
initialDateTime = initialDateTime.AddDays(7);
break;
case DateUtils.TimeType.Months:
initialDateTime = initialDateTime.AddMonths(1);
break;
case DateUtils.TimeType.Years:
initialDateTime = initialDateTime.AddYears(1);
break;
default:
initialDateTime = initialDateTime.AddDays(1);
break;
}
return initialDateTime;
}
All of which executes without any issues.
Then when the series have been added i use the following loop in my Form class:
List<Series> chart = ((EmailModel)_controller.GetFactory().GetModel("Email")).GetEmailChart(from, to, current_timetype);
test_chart.Series.Clear();
foreach (Series s in chart)
{
test_chart.Series.Add(s);
}
Which produces the following chart:
if you look closely then you will see that it has repeated the data 7 times.
i just don't know what the issue is.
Can anyone tell me what i am doing wrong?
Please tell me if you need more info or code i will check back every often and update my question.
As i see the partern you repeat 7 times 7 column.
You have to add 1 serie.
Try:
test_chart.Series.Add(s);
Whitout the foreach!

is there any way to simplify this double conditional clauses structure?

for example
if (x=="A)
switch (y)
{
case "1": Do1();break;
case "2": Do2();break;
case "3": Do3();break;
}
else if (x=="B")
switch (y)
{
case "1": Do4();break;
case "2": Do5();break;
case "3": Do6();break;
}
else
switch (y)
{
case "1": Do7();break;
case "2": Do8();break;
case "3": Do9();break;
}
I wish I could do the following, however it has many redundant checks.
if (x=="A" && y=="1")
Do1();
else if (x=="A" && y=="2")
Do2();
else if (x=="A" && y=="3")
Do3();
else if (x=="B" && y=="1")
Do4();
else if (x=="B" && y=="2")
Do5();
else if (x=="B" && y=="3")
Do6();
else if (x=="C" && y=="1")
Do7();
else if (x=="C" && y=="2")
Do8();
else if (x=="C" && y=="3")
Do9();
Suggestion to introduce OOPS is really great, please do not ignore that comment. For time being you can write your code like this.
var combinedText = x+y;
switch(combinedText)
{
case "A1": Do1(); break;
case "A2": Do2(); break;
case "A3": Do3(); break;
case "B1": Do4(); break;
case "B2": Do5(); break;
case "B3": Do6(); break;
case "C1": Do7(); break;
case "C2": Do8(); break;
case "C3": Do9(); break;
}
Your code currently has two responsibilities - deciding what set of methods to execute (varible x) and deciding which exact method to execute (varible y). Simplest option to make code much more clear - split this responsibilities and extract methods, that will decide which method from set of methods to call
switch (x)
{
case "A": DoA(y); break;
case "B": DoB(y); break;
default:
DoDefault(y); break;
}
Now your caller code is simple. And here is one of DoX methods:
private void DoA(string y)
{
switch (y)
{
case "1": Do1(); break;
case "2": Do2(); break;
case "3": Do3(); break;
}
}
Other option is to make .net to decide which set of methods to call, by using polymorphism. But in your simple case with only one switch(x) block, I will not recommend to do that. If your real code is more complex, then consider to extract classes which will hold set of functionality (Do1, Do2, Do3) and will decide upon that functionality execution. E.g. calling code:
IDo ido = CreateIDo(x);
ido.Do(y);
Yes, that's all. Extremely clean. Here is IDo interface creation code:
public static IDo CreateIDo(string x)
{
switch (x)
{
case "A": return new A();
case "B": return new B();
default:
return new C();
}
}
And here is class A, that encapsulates first set of methods and decisions upon executing them:
public interface IDo
{
void Do(string y);
}
public class A : IDo
{
public void Do(string y)
{
switch (y)
{
case "1": Do1(); break;
case "2": Do2(); break;
case "3": Do3(); break;
}
}
private void Do1() { }
private void Do2() { }
private void Do3() { }
}
Again, use this in case your real code is more complex.
I would use an IEnumerable collection of Tuples and an Action delegate to define your list of methods to be called, create the list as a private field or in the class initialiser, or to be flexible you can add Tuples to a public property as needed. If you need to pass in parameters use one of the overloaded versions of the Action delegate ie: Action(t1, t2) etc.
If you need a return value use the Func delegate as per the other answer.
IEnumerable<Tuple<string, string, Action>> actions = new List<Tuple<string, string, Action>>() {
Tuple.Create<string, string, Action>("A", "1", SomeMethod1),
Tuple.Create<string, string, Action>("A", "2", SomeMethod2)
};
string x = "A";
string y = "2";
var action = actions.FirstOrDefault(t => ((t.Item1 == x) && (t.Item2 == y)));
if (action != null)
action.Item3();
else
DoSomeDefaultMethod();
public void SomeMethod1() { // Whatever you want to do }
public void SomeMethod2() { // Whatever you want to do }
public void DoSomeDefaultMethod() { // Default Method }
void Main()
{
Dictionary<string, Action> d = new Dictionary<string, Action>()
{
{"A1", Do1},
{"A2", Do2},
{"A3", Do3},
{"B1", Do4},
{"B2", Do5},
{"B3", Do6},
{"1", Do7},
{"2", Do8},
{"3", Do9}
};
var x = "A";
var y = "1";
var action = x == "A" || x == "B" ? x + y : y;
if (d.ContainsKey(action))
d[action]();
}
public void Do1() {}
public void Do2() {}
public void Do3() {}
public void Do4() {}
public void Do5() {}
public void Do6() {}
public void Do7() {}
public void Do8() {}
public void Do9() {}
EDIT
I remembered about this fluent functional switch:
var sw = new Switch<string>(action)
.Case("A1", s => Do1())
.Case("A2", s => Do2());
Consider this if you don't want to change much of your current structure,(and don't want to create new types etc.)
Add them to tuples like below
var tuples = new List<Tuple<string,string,Func<>>()>(); // Func should be of your Do() type
Add your conditional data with the related funcs to the list
tuples.Add(new Tuple<string,string,Func<>>("A","1", Do1()));
...
Just call it when required using your conditionals directly
var function = tuples.Where(x => x.item1 == "A" && x.item2 == "1").Select(x => x.item3);
function.Invoke(); // to call it.
Now if you got more conditionals in future, you can just add them to the list without changing any code.
Use some thing like this . only three if would do.
if (x == "A")
{
int a = (y == "1") ? do1() : ((y == "2") ? do2() : do3());
}
}
int do1() { return 10; }
int do2() { return 10; }
int do3() { return 10; }
I guess the same kind of switch on X is performed in more than one place in your code, if so kindly refactor it and use polymorphism instead
If X is string first replace the typecode with class and use polymorphism.

Categories