Math with Enums (e.g. DayOfWeek) in C# - c#

Why is it that the following code won't work:
endDate.AddDays(7-endDate.DayOfWeek);
While this will:
endDate.AddDays(0-endDate.DayOfWeek + 7);
?
(By "won't work" I mean results in the following compilation error: "cannot convert from 'System.DayOfWeek' to 'double'")

To expand upon what Lasse said (or rather, make it a little more explicit).
Because 0 is convertable to an Enum type,
0 - endDate.DayOfWeek becomes
(DayOfWeek)0 - endDate.DayOfWeek
And since you can subtract one enum from another and get an integer difference:
(DayOfWeek)0 - endDate.DayOfWeek == (int)endDate.DayOfWeek
Thus, since the result of the subtraction is an int, you can then add 7 to it.
endDate.AddDays(0-endDate.DayOfWeek + 7);
So, if Monday's Enum value is 1
0 - endDate.DayOfWeek == -1 + 7 == 6
However, you can't do the reverse.
endDate.DayOfWeek - 0 + 7,
because the result type of the calculation is dependant upon the leftmost side. Thus, while 0 - endDate.DayOfWeek results in an integer, endDate.DayOfWeek - 0 results in an enum DayOfWeek.
Most interestingly, you could use this side-effect to get the value of an enum without casting, though I would consider this hackish and confusing... thus to be avoided.
int enumValue = -(0 - endDate.DayOfWeek);

This is very interesting. The right way to do this is:
endDate.AddDays(7 - (int)endDate.DayOfWeek);
But, your question isn't about a solution, but a reason for the behavior. It has something to do with the way the compiler treats a zero. Either line fails if no zero is present, while both lines work if a zero is present.

You can subtract two enum values to get their integer value difference:
using System;
namespace ConsoleApplication10
{
public enum X { A, B, C, D }
public class Program
{
static void Main()
{
var x = X.D + X.A;
Console.Out.WriteLine(x);
Console.In.ReadLine();
}
}
}
Will print out 3.
But you can't add, probably makes no sense.
In the case of "0", 0 is auto-convertible to all enum types, so basically "0 - enumvalue" means the same as "(enumtype)0 - enumvalue", which again works.

Related

C# What does int i = +1 mean?

I was browsing around stack overflow and I encountered this question:
check for duplicate filename when copying files in C#
In this question, this little gem existed:
int i = +1
I have never seen this syntax before. So I opened up the interactive C# window in visual studio:
Microsoft (R) Roslyn C# Compiler version 1.3.4.60902
Loading context from 'CSharpInteractive.rsp'.
Type "#help" for more information.
> int i = +1;
> i
1
> +1 == 1
true
Is this similar to +=? Is this some new syntax? What is this operator? How is it different than a normal variable declaration?
That's the unary plus operator. From the documentation:
The result of a unary + operation on a numeric type is just the value of the operand.
In most sane contexts1 where you're writing code, it'll be optional (+1 is the same as 1 if we're writing literals).
It mostly exists for symmetry with the unary minus operator.
Most of the time, you'll not write code containing it, but if you're generating code it can be handy to be able to apply a unary operator either way2.
It has no relation to +=.
1Insane code could override this operator for custom types and make it more than a no-op. But I'd love to understand a use case where it makes code more understandable, which should be the main aim of most code.
2E.g. imagine you're chaining a set of operations together and for each additional element, you wish to change the sign of the overall result. This lets you just store an operator and apply it blindly when you finally decide to output a result
For for all signed numeric types the positive-sign is optional. So,
+1 == (+1) == 1
+1.0 == (+1.0) == 1.0
+1L == (+1L) == 1L
+1.0m == (+1.0m) == 1.0m
Do not confuse
int i = +1; // Assigns 1
which is the same as
int i = (+1); // Assigns 1
or simply
int i = 1; // Assigns 1
with
int i += 1; // INCREMENT!
which increments i.
In C# terms there is a binary + operator (the addition operator as in int i = 3 + 4;) and a unary + operator (the plus sign as in int i = +1;).
Think of it the way you think of
int i = -1
and it becomes obvious

String.CompareTo with case

Sample code to illustrate:
int res1 = "a".CompareTo("A"); // res1 = -1
int res2 = "ab".CompareTo("A"); // res2 = 1
I'm seeing res1 = -1, and res2 = 1 at the end, which was a bit unexpected.
I thought res1 would return 1, since on an ASCII chart "A" (0x41) comes before "a" (0x61).
Also, it seems strange that for res2, the length of the string seems to make a difference. i.e. if "a" comes before "A" (as res1 = -1 indicates), then I would have thought that "a"withAnythingAfterIt would also come before "A"withAnythingAfterIt.
Can someone shed some light?
Thanks.
This is the expected behavior. String.CompareTo(string) does a culture sensitive comparison, using its sort order. In fact it calls CultureInfo to do the job as we can see in the source code:
public int CompareTo(String strB) {
if (strB==null) {
return 1;
}
return CultureInfo.CurrentCulture.CompareInfo.Compare(this, strB, 0);
}
Your current culture puts 'A' after 'a' in the sort order, since it would be a tie, but not after 'ab' since clearly 'ab' comes after either 'a' or 'A' in most sort orders I know. It's just the tie breaking mechanism doing its work: when the sort order would be the same, use the ordinal value!
From MSDN
Definition
Compares this instance with a specified Object and indicates whether
this instance precedes, follows, or appears in the same position in
the sort order as the specified Object.
Note
The CompareTo method was designed primarily for use in sorting or
alphabetizing operations. It should not be used when the primary
purpose of the method call is to determine whether two strings are
equivalent. To determine whether two strings are equivalent, call the
Equals method.
CompareTo is an instance method.
If the first string is bigger, the result is 1. If the first string is smaller, the result is -1. If both strings are equal, the result is 0. The number essentially indicates how much "larger" the first string is.
Console.WriteLine("a".CompareTo("A")); // -1
Console.WriteLine("ab".CompareTo("A")); // 1
Console.WriteLine("a".CompareTo("a")); // 0
Console.WriteLine("ab".CompareTo("AB")); // -1
Console.WriteLine("A".CompareTo("a")); // 1
Console.WriteLine("AB".CompareTo("ab")); // 1
Console.WriteLine("A".CompareTo("A")); // 0

Alternative to operand && (C#)

so I'm trying to make a code with &&. However, when I put that in, it said that I couldn't apply the operand to it.
In specific, it reads: Operator "&&" cannot be applied to operands of type 'Server.Enums.PokemonType' and 'Server.Enums.PokemonType'
However, I need to be able to link these two things so I can make the code be two PokemonTypes. So is there any alternative or work-around for not being able to use &&?
If you need it, this is my code:
case 225:
{
//Flying Press -- INCOMPLETE, needs Flying-type
setup.Move.Element = Enums.PokemonType.Fighting && setup.Move.Element = Enums.PokemonType.Flying;
if (setup.Defender.VolatileStatus.GetStatus("Minimize") != null)
{
setup.Multiplier *= 2;
setup.Move.Accuracy = -1;
}
}
break;
The system defined && operator only supports boolean operands. The & operator will work for enums (because it also works on all integer types, which the enums are based on). Of course, if you want an enum that represents the combination of two flag values then you'll want to OR them together (using |), not AND them together.
To add multiple values to a enum variable you need to declare the enum with [Flags] attribute.
So your enum would be:
[Flags]
public enum PokemonType
{
Fighting = 1 << 0,
Flying = 1 << 1,
Normal = 1 << 2,
Dragon = 1 << 3,
}
Define enumeration constants in powers of two, that is, 1, 2, 4, 8, and so on. This means the individual flags in combined enumeration constants do not overlap
Then assign using Enums.PokemonType.Fighting | Enums.PokemonType.Flying so it is possible to track all values assigned to it later.

How do I retrieve a value from a [Flag] enum property? [duplicate]

This question already has answers here:
What does the [Flags] Enum Attribute mean in C#?
(14 answers)
Closed 7 years ago.
Say I have an enum defined like so:
[Flags]
public enum LogLevel
{
None = 1,
Pages = 2,
Methods = 4,
Exception =8
}
and a class like:
public static class Log
{
public static LogLevel Level = LogLevel.Methods | LogLevel.Pages;
public static void EnterPage([CallerFilePath]string filePath = "")
{
if (Level == //What value here to check if Level includes Pages?)
{
//Log
}
}
What value do I need to equate Level to to check whether the enum includes Pages?
First of all, flags must have a None = 0 value, because otherwise there's no way to represent a 0 mask (i.e. no value).
Once you've fixed it, you can check if some enumeration value is in some given flag using Enum.HasFlag or the bit-wise & operator:
Level.HasFlag(LogLevel.Pages);
...or:
(Level & LogLevel.Pages) == LogLevel.Pages
Finally, when you implement a flags enumeration, usually enumeration identifier is expressed in plural. In your case, you should refactor LogLevel to LogLevels.
Why &?
Each enumeration value represents a bit in a complete mask. For example, None would be 0, but it could be also represented as 0, 0, 0 where each 0 is one of possible enumeration values in LogLevels. When you provide a mask like LogLevels.Pages | LogLevels.Methods, then the mask is 1, 1, 0.
In order to check if Pages is within the mask, you use a logical AND comparing the mask with one of possible enumeration values:
1, 1, 0 (LogLevels.Pages | LogLevels.Methods)
1, 0, 0 AND (LogLevels.Pages)
--------
1, 0, 0
1 and 1 (true and true == true)
1 and 0 (true and false == false)
0 and 0 (false and false == false).
The whole AND is like isolating the tested enumeration value. If the resulting mask equals the enumeration value, then the mask contains the enumeration value.
Some OP concern
OP said in some comment:
Just a quick question on zero value. here it states that You cannot
use the None enumerated constant in a bitwise AND operation to test
for a flag because the result is always zero. Does that mean if I have
a 0 value I cannot use & and must use HasFlag?
None (i.e. 0) won't be a member of a mask, because 0 doesn't exist. When you produce a mask you're using the OR | logical operator, which is, at the end of the day, an addition.
Think about 1 + 0 == 1. Would you think checking if 0 is within 1 is ever possible?
Actually, the None = 0 value is required to be able to represent and empty mask.
Finally, HasFlag does the AND for you, it's not a magical solution, but a more readable and encapsulated way of performing the so-called AND.
like this
if (Level.HasFlag(LogLevel.Pages))
{
//todo
}

What is the behaviour of FlagsAttribute Enum in C#?

I have the following code:
namespace ConsoleApplication1
{
internal class Program
{
[FlagsAttribute]
private enum RenderType
{
DataUri = 0,
GZip = 1,
ContentPage = 2,
ViewPage = 4,
HomePage = 8
}
private static void Main()
{
// 4.
// Set a new enum in three statements.
RenderType type2 = RenderType.ViewPage;
// 5.
// See if the enum contains this flag.
if ((type2 & RenderType.ViewPage) == RenderType.ViewPage)
{
Console.WriteLine("ViewPage");
}
if ((type2 & RenderType.DataUri) == RenderType.DataUri)
{
Console.WriteLine("DataUri");
}
if ((type2 & RenderType.GZip) == RenderType.GZip)
{
Console.WriteLine("GZip");
}
}
}
}
Whenever I run this code, it gives me an output of:
ViewPage
DataUri
I want output of just ViewPage as I am giving the value to my enum ViewPage.
Can anyone help me here? Why is this? Is there anything wrong with my Enum declaration or code?
You have declared DataUri = 0 so
(type2 & RenderType.DataUri) == RenderType.DataUri
will always evaluate to true.
Start your valid enum values at 1.
Any number bitwise anded with zero is zero. Start the enum with one and increase by powers of two. Also, a better understanding of binary numbers and bitwise operators will help
DataUri is 0: so x & DataUri is always zero!
Try this:
if(type2 != RenderType.DataUri) {
if ((type2 & RenderType.ViewPage) == RenderType.ViewPage)
{
Console.WriteLine("ViewPage");
}
if ((type2 & RenderType.GZip) == RenderType.GZip)
{
Console.WriteLine("GZip");
}
}
When using Bitmasks the value 0 usually indicates a NONE-Flag. So you should start to count from 1 to 2^n, which is a better practise IMHO:
[FlagsAttribute]
private enum RenderType
{
None = 0,
DataUri = 1,
GZip = 2,
ContentPage = 4,
ViewPage = 8,
HomePage = 16
}
Because x & 0 always equals zero.
Don't specify 0 (zero) as a possible value for a [Flags] enum. Remember that a [Flags] enum is a bit field, and a value of zero doesn't really map into any of the fields, so it will always return true.
From the Framework Design Guidelines by Krzysztof Cwalina:
Avoid using flag enum values normal members that are negative or zero.
Negative values produce unexpected/confusing results in bitwise operations. An enum value of zero creates problems with and operations, etc:
The reason is that RenderType.DataUri has the value 0.
What your code does is to inspect the bitwise configuration of the type2 enum variable by performing a bitwise and operation between type2 and the enum member it's testing for.
In your example, type2 has the value 4, which is 0100 in binary (up to the 4 bits that your enum requires). When you test for RenderType.GZip (0001), it does the following calculation:
0100 & 0001 = 0000
Since 0000 != 0001, the RenderType.GZip bit is not set in type2. However, 0100 & 0000 is always 0000, so you'll always get true when checking for RenderType.DataUri.
Essentially, a Flags enum uses a different bit for each of its members, but since 0 doesn't represent a bit in an integer, it won't behave as expected.
As others have said you should start Flags enums at 1 due to how binary arithmetics work. I just want to add that you may want to use the HasFlag method (I believe new in .NET 4.0) to check the flags:
if(type2.HasFlag(RenderType.ViewPage))
{
...
}
http://msdn.microsoft.com/en-us/library/system.enum.hasflag.aspx

Categories

Resources