Why is this not working? Entities.CurHP - Entities.RIntDamage - c#

Both are integers, but it keeps giving me the error
"Only assignment, call, increment, decrement, await, and new object
expressions can be used as a statement"
I have tried using different operators but none give me my desired answer. If Entities.RIntDamage = 5 and Entities.CurHP = 10 shouldnt the answer be 5?

Because you aren't actually doing anything.
As the error is trying to tell you, statements in C# must have some kind of effect.
Writing a - b has no effect.
You might want to store the result of that in a variable, or pass it to a function.

I assumed it would change the Entities.CurHP
Your assumption is reasonable, but requires slightly different syntax. Use -= instead of -. That is, use:
Entities.CurHP -= Entities.RIntDamage;
The = tells C# to store the result (in Entities.CurHP).
Similarly, Entities.CurHP -= 6 + 5; would subtract 11 from Entities.CurHP and store the result in Entities.CurHP.

Related

In C# ternary operator giving error: Only assignment, call, increment, decrement, and new object expressions can be used as a statement

I have the following C# code -
using System;
class Program
{
static void Main()
{
int number = 1;
int isNumber10;
(number==10)?(isNumber10=1):(isNumber10=0);
Console.WriteLine(isNumber10);
}
}
On compilation it gives me the error -
error CS0201: Only assignment, call, increment, decrement, and new
object expressions can be used as a statement
In C I am used to the following code -
#include <stdio.h>
int main(){
int isNumber10;
int number = 1;
(number==10)?(isNumber10=1):(isNumber10=0);
printf("%d\n",isNumber10);
return 0;
}
And this code is running perfectly.
Now, the two programs are exactly same. So why is it running in C but not in C#?
The ternary operator is an expression that cannot be used as a statement. In contrast, an assignment is an expression that can be promoted to a statement. (hence the error message referring to "assignment" expressions)
What you want is:
isNumber10 = number == 10 ? 1 : 0;
Here you are using the ?: operator as an expression that resolves to one of the two values (1 or 0) and is then assigned to the variable isNumber10.
To have a little fun with this, if you created this method:
public void M<T>(T value)
{
}
And you called it like:
M((number==10)?(isNumber10=1):(isNumber10=0));
It would work fine. The problem is just that the C# grammar does not allow most naked expressions to live in a context in which the value of the expression is not consumed. (Remember, the defining difference between an expression and a statement is that an expression produces an expression, but a statement does not) Some expressions are allowed outside of this guidance -- for example invoking a method that returns a value. These become in the technical parlance an "expression statement". And usefully, the only candidates for expressions that can be promoted to statements are exactly delineated by the error message in your question's title.
Most of us think of assignments as statements, but it is more fundamentally an expression. (it returns the value assigned while simultaneously performing the assignment). That's why that empty call to M will actually accomplish what you want. (not that it's very readable)
From your comment, I'll add this comment as part of my answer:
The only error of yours is the simple fact that the C# grammar doesn't allow it. It certainly could, but well, it does not. I'm reminded about how the when operator in SQL is an expression (meaning you can say set i = when x is null then 'A' else 'B') whereas in C# such a usage would be invalid (since the switch statement is not an expression -- it cannot return a value)
try this:
int number = 1;
int isNumber10 = (number == 10) ? 10 : 0;
Console.WriteLine(isNumber10);
The problem is that C grammar and C# grammar are different.
I am giving a simple example -
There is a man John
In C the following statement is valid -
(John has beard)?(Ask John to save):(ask John to not save);
Here John has to be referred twice.
Also the following statement is valid -
Ask John to = (John has beard)? (save):(not save);
Here John is referred only once.
But In C# only the following statement is valid -
Ask John to = (John has beard)? (save):(not save);
Like that in the given code -
Correct C Syntax -
(number==10)?(isNumber10=1):(isNumber10=0);
as well as -
isNumber10 = (number==10)? 1:0;
but in C# only the following syntax is Correct -
isNumber10 = (number==10)? 1:0;

In C#, can assignment and parameter passing happen in a single statement?

I am trying to do
string answer = (5 + 6).ToString();
Console.WriteLine(answer);
I would like to find out if assignment and parameter passing can happen simultaneously in a single statement for C#. The compiler doesn't like the following code.
Console.WriteLine(string answer = (5 + 6).ToString());
I would like to find out if assignment and parameter passing can happen simultaneously in a single statement for C#.
They can, but variable declaration can't. This code is not legal:
Console.WriteLine(string answer = (5 + 6).ToString());
But this code is legal:
string answer;
Console.WriteLine(answer = (5 + 6).ToString());
And thanks to assignment chainging, it will output the value 11. But it's probably not the best coding style you could use. For preference, I'd write it like this:
string answer = (5 + 6).ToString();
Console.WriteLine(answer);
It's also not best to think of it as "simultaneous". They are in the same C# statement, but won't be in the same IL statement when compiled, and are not atomic.
Edit: Never mind, I am rusty apparently. Check out the other answer: assignment expressions do exist in C#, but they cannot contain variable declarations.
In C#, assignment is a statement and not an expression. Statements that are not expressions do not have values (unlike C++, where an assignment has a value, namely, the newly assigned value). This is mainly to prefer errors such as if (x=5) ..., since x=5 cannot have a value, this code will fail to build.
If you want to declare, assign, and then use, you're pretty much out of luck, as declaration cannot be used as an expression.
If you only want to assign and use, then using a function with a ref parameter could take care of it.
Example:
T AssignAndGet<T>(ref T variable, T result) {
variable = result;
return result;
}
which could be used as:
string x;
Console.WriteLine(AssignAndGet(x, (5+3).ToString()));

Is it possible to use IIF within SUM in a C# DataColumn.Expression?

This is the expression I'm trying to evaluate:
Sum(IIF(QUALITY<=9.0,1.0,0.0))
The problem is that
string expr = "Sum(IIF(QUALITY<=9.0,1.0,0.0))";
dataTable.Compute(expr, "")
throws an error saying
Syntax error in aggregate argument: Expecting a single column argument with possible 'Child' qualifier.
The main challenge is that I can't rewrite the expression by hand, since it's coming to my program in a string from an RDL file, so it originally looks like
Sum(IIF(Fields!QUALITY.Value<=9.0,1.0,0.0))
and my program needs to automatically convert that into a string that will be a valid expression when passed to dataTable.Compute(). I determined from Microsoft's documentation of the Compute method that C# doesn't like the "Fields!" or ".Value" parts of the syntax, and by removing them I have simpler expressions working fine; for example, these statements both return the expected values:
dataTable.Compute("Sum(QUALITY)");
dataTable.Compute("Count(QUALITY)");
Is it possible to do what I'm trying to do? I feel like I should just need a slight change in syntax somewhere for it to work, but I haven't been able to find an answer on the internet and it's getting pretty frustrating.
Here are some of the things I've tried so far, to no avail:
Sum(IIF([QUALITY]<=9.0,1.0,0.0))
Sum(Convert(IIF(QUALITY<=9.0,1.0,0.0), 'System.Double'))
Sum(IIF(Convert(QUALITY, 'System.Double')<=9.0,1.0,0.0))
One way to do this might be to add an aggregate column to the DataTable with the Expression set to IIF(QUALITY<=9.0,1.0,0.0).
dataTable.Columns.Add("AggregateColumn", typeof(double), "IIF(QUALITY<=9.0,1.0,0.0)");
then sum or count the aggregate column.
IIF(condition, value1, value2) returns value1 if condition is true, and value2 otherwise. Therefore, your original statement counts the number of all Quality fields with value <= 9. You can use the overload which includes a filter parameter to achieve this.
dataTable.Compute("Count(QUALITY)","QUALITY <= 9");
MSDN documentation.
Edit: Missed the dynamic requirement on the first go-round.
The error occurs because IIF makes this a two column operation, and Compute does not allow two column operations within aggregate functions. Meaning that Compute("IIF(Quality <= 9, 1, 0)") is valid, but Compute("Sum(IIF(Quality <= 9, 1, 0))") is not. You could be using IIF(Quality <= 9, Quality, SomeOtherColumn) instead of literals as the latter two arguments to IIF, and it seems that the parser doesn't know the difference.
You could use Joe's solution, or add more string processing in order to separate out coniditionals and move them to the filter parameter. Joe's answer is much more sensible than trying to reimplement the string parsing that happens behind the scenes in Compute.

Changing variables outside of Scope C#

I'm a beginner C# programmer, and to improve my skills I decided to give Project Euler a try. The first problem on the site asks you to find the sum of all the multiples of 3 and 5 under 1000. Since I'm essentially doing the same thing twice, I made a method to multiply a base number incrementally, and add the sum of all the answers togethor.
public static int SumOfMultiplication(int Base, int limit)
{
bool Escape = false;
for (int mult = 1; Escape == true; mult++)
{
int Number = 0;
int iSum = 0;
Number = Base * mult;
if (Number > limit)
return iSum;
else
iSum = iSum + Number;
}
regardless of what I put in for both parameters, it ALWAYS returns zero. I'm 99% sure it has something to do with the scope of the variables, but I have no clue how to fix it. All help is appreciated.
Thanks in advance,
Sam
Your loop never actually executes:
bool Escape = false;
for (int mult = 1; Escape == true; mult++)
Escape is set to false initially, so the first test fails (Escape == true returns false) and the body of the loop is skipped.
The compiler would have told you if you were trying to access variables outside of their defined scope, so that's not the problem. You are also missing a return statement, but that is probably a typo.
I would also note that your code never checks if the number to be added to the sum is actually a multiple of 3 or 5. There are other issues as well (for example, iSum is declared inside of the loop and initialized to 0 after each iteration), but I'll let you work that one out since this is practice. The debugger is your friend in cases like these :)
EDIT: If you need help with the actual logic I'll be happy to help, but I figure you want to work it out on your own if possible.
As others have pointed out, the problem is that the control flow does not do what you think it does. This is a common beginner problem.
My suggestion to you is learn how to use your debugger. Beginners often have this strange idea that they're not allowed to use tools to solve their coding problems; that rather, they have to reason out the defect in the program by simply reading it. Once the programs become more than a page long, that becomes impossible for humans. The debugger is your best friend, so get to know its features really well.
In this case if you'd stepped through the code in the debugger you'd see that the loop condition was being evaluated and then the loop was being skipped. At that point you wouldn't be asking "why does this return zero?", you'd be asking "why is the loop body always skipped?" Clearly that is a much more productive question to ask since that is actually the problem here.
Don't write any code without stepping through it in the debugger. Watch every variable, watch how it changes value (the debugger highlights variables in the watch windows right after they change value, by the way) and make sure that the control flow and the variable changes are exactly as you'd expect. Pay attention to quiet doubts; if anything seems out of the ordinary, track it down, and either learn why it is correct, or fix it until it is.
Regarding the actual problem: remember that 15, 30, 45, 60... are all multiples of both three and five, but you only want to add them to the sum once. My advice when solving Project Euler problems is to write code that is as like what you are trying to solve as is possible. Try writing the problem out in "pseudocode" first. I'd pseudocode this as:
sum = 0
for each positive number under 1000:
if number is multiple of three or five then:
add number to sum
Once you have that pseudocode you can notice its subtleties. Like, is 1000 included? Does the problem say "under 1000" or "up to 1000"? Make sure your loop condition considers that. And so on.
The closer the program reads like the problem actually being solved, the more likely it is to be correct.
It does not enter for loop because for condition is false.
Escape == true
returns false
Advice:
Using for loop is much simpler if you use condition as limit for breaking loop
for (int mult = 1; something < limit; mult++)
This way in most cases you do not need to check condition in loop
Most programming languages have have operator modulo division.
http://en.wikipedia.org/wiki/Modulo_operation
It might come handy whit this problem.
There are several problems with this code. The first, and most important, is that you are using the Escape variable only once. It is never set to false within your for loop, so it serves no purpose whatsoever. It should be removed. Second, isum is declared within your for loop, which means it will keep being re-initialized to 0 every time the loop executes. This means you will only get the last multiple, not the addition of all multiples. Here is a corrected code sample:
int iSum = 0;
for(int mult = 1; true; mult++)
{
int Number = Base * mult;
if(Number > limit)
return iSum;
else
iSum += Number;
}

Is there any plugin for VS or program to show type and value etc... of a C# code selection?

What I want to do is be told the type, value (if there is one at compile-time) and other information (I do not know what I need now) of a selection of an expression.
For example, if I have an expression like
int i = unchecked((short)0xFF);
selecting 0xFF will give me (Int32, 255), while selecting ((short)0xFF) will give me (Int16, 255), and selecting i will give me (Int32, 255).
Reason why I want such a feature is to be able to verify my assumptions. It's pretty easy to assume that 0xFF is a byte but it is actually an int. I could of course refer to the C# Language Specifications all the time, but I think it's inefficient to have to refer to it everytime I want to check something out. I could also use something like ANTLR but the learning curve is high.
I do intend to read the entire specs and learn ANTLR and about compilers, but that's for later. Right now I wish to have tools to help me get the job done quickly and accurately.
Another case in point:
int? i = 0x10;
int? j = null;
int x;
x = (i >> 4) ?? -1;//x=1
x = (j >> 4) ?? -1;//x=-1
It may seem easy to you or even natural for the bottom two lines in the code above. (Maybe one should avoid code like these, but that's another story) However, what msdn says about the null-coalescing operator is lacking information to tell me that the above code ((i>>4)??) is legal (yet it is, and it is). I had to dig into grammar in the specs to know what's happening:
null-coalescing-expression
conditional-or-expression
conditional-and-expression
exclusive-or-expression
and-expression
equality-expression
relational-expression
shift-expression
shift-expression right-shift additive-expression
... (and more)
Only after reading so much can I get a satisfactory confirmation that it is valid code and does what I think it does. There should be a much simpler way for the average programmer to verify (not about validity, but whether it behaves as thought or not, and also to satisfy my curiosity) such code without having to dive into that canonical manual. It doesn't necessary have to be a VS plugin. Any alternative that is intuitive to use will do just as well.
Well, I'm not aware of any add-ins that do what you describe - however, there is a trick you can use figure out the type of an expression (but not the compile-time value):
Assign the expression to a var variable, and hover your mouse over the keyword var.
So for example, when you write:
var i = unchecked((short)0xFF);
and then hover your mouse over the keyword var, you get a tooltip that says something like:
Struct System.Int16
Represents a 16-bit signed integer.
This is definitely a bit awkward - since you have to potentially change code to make it work. But in a pinch, it let's you get the compiler to figure out the type of an expression for you.
Keep in mind, this approach doesn't really help you once you start throwing casts into the picture. For instance:
object a = 0xFF;
var z = (string)a; // compiles but fails at runtime!
In the example above, the IDE will dutifully report that the type of var z is System.String - but this is, of course, entirely wrong.
Your question is a little vague on what you are looking for, so I don't know if "improved" intellisense solves it, but I would try the Productivity Power Tools.

Categories

Resources