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

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()));

Related

Is there another "is" operator in C#? [duplicate]

This question already has answers here:
Why does is operator behave like == operator?
(3 answers)
Using "is" keyword with "null" keyword c# 7.0
(2 answers)
Closed 2 years ago.
I was teaching my students how to write a function. I used a simple algorithm to determine if a char value is an actual letter (and not a digit or something else).
So I actually typed what my student said (playing dumb on purpose): "if (letter is 'A') {...}"
To my surprise this didn't cause a compiler error. I added the same check for 'B' and 'C' and my program can now determine that A, B and C are indeed letters.
Why does that work? And WHAT exactly am I comparing here?
I'm not actively using type comparisons, which is what the internet keeps turning up.
I did an additional experiment with other values:
char l = 'A';
if (l is 'A')
{
Console.WriteLine("l 'A'...");
}
if (l is "A")
{
// Doesn't compile.
}
int x = 15;
if (x is 15)
{
Console.WriteLine("X is 15.");
}
if (x is 5.6)
{
// Also doesn't compile.
}
As far as I can tell "is" functions as an extended version of the equality (==) operator that also enforces the same type. But I can't find any documentation on it.
is might have two meanings, depending on which version of C# you have.
In older C# versions, is was short for "is assignable to" or "is assignable from", depending on how you read the code in your head. It wouldn't work for the code in your class because it expects a type on the right-hand side, but I include it here for completeness. It's also useful as an efficient and portable null check, ie variable is object is a better way to write variable != null1.
In newer C# versions, is can also be used for pattern matching. This was introduced in C# 72 and extended in C# 8, with more coming in 9. Specifically, the code in the question creates a Constant Pattern expression.
Here's another fun way to see this work. Coming in C# 9, instead of writing a check like this:
if (!string.IsNullOrEmpty(mystring))
You could instead write3
if (mystring is {Length:>0})
Which is nice because it's shorter and you could make an argument removing the negation makes it easier to understand.4
At least, according to one of the developers on the C# team at Microsoft. But what would he know? He only built the thing.
Really, C# 6 if you count exception filters.
Jared Parsons again.
I'd reject that argument on the grounds any gains in removing the negation are less than the subtlety introduced in how we validate for null. But you could try the argument ;) And before anyone asks, I have no idea at this time how the two options perform.

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;

(string)combination Purpose?

I'm following an exercise which tasks me to...
"Declare two variables of type string with values "Hello" and "World".
Declare a variable of type object. Assign the value obtained of
concatenation of the two string variables (add space if necessary) to
this variable. Print the variable of type object".
Now here was my original solution:
string hi = "Hello";
string wo = "World";
object hiwo = hi + " " + wo;
Console.WriteLine(hiwo);
Console.ReadLine();
I found a good website that gives sample solutions of the exercises I am going through, which I have started to go through comparing to my answers, In this one I noticed I was nearly spot on, apart from an extra line. I've modified my original code to illustrate the comparison more easily.
My modified code:
string firstWord = "Hello";
string secondWord = "World";
object combination = firstWord + " " + secondWord;
Console.WriteLine(combination);
Given Solution:
string firstWord = "Hello";
string secondWord = "World";
object combination = firstWord + " " + secondWord;
string a = (string)combination;
Console.WriteLine(a);
I believe understanding this extra line is the purpose of the exercise. So my question is why is the extra line exists and what the benefits are to having it? The section of the book is understanding types and variables.
The extra line is a type cast:
A cast is a way of explicitly informing the compiler that you intend to make the conversion and that you are aware that data loss might occur.
Usually, a cast doesn't really return a different object. It just checks if the object is, at runtime, of the type you're casting to. That is, the expression firstWord + secondWord returns an object of type string. Assigning it to a variable of type object doesn't change the fact it's really a string. Similarly, doing (string) combination doesn't return a different object – it just tells the compiler that the expression is of type string. (If combination wasn't really a string, the check would fail and throw an exception.)
In this case there is no benefit to having it there I can see. Console.WriteLine(object) converts the object to a string internally, and an object that is already a string will just "convert" to itself.
In your solution when you call
Console.WriteLine(Combination)
.ToString() method is called internally. Therefore you don't feel the difference.
From MSDN
If value is null, only the line terminator is written. Otherwise, the ToString method of value is called to produce its string representation, and the resulting string is written to the standard output stream.
Whereas in the given solution object is first converted to string and then written.
To understand the difference let's take another example
TextBox tb = new TextBox();
Console.WriteLine(tb);
output would be System.Windows.Forms.TextBox, Text: that is the type of object
In your version what is happening in the line Console.WriteLine is a call to the virtual ToString method, which because of being virtual is in fact executed in its version implemented in the string class (which just returns the string).
The given solution explicitly casts the object into string. The difference is thus in increased readability - less things are happening behind the scene - it is made explicit that you're operating on a string instance.
The extra line is basic casting the object to a string type in order for it to be printed out.
Another way would be...
string firstWord = "hello";
string "secondWord = "world";
object combination = string.Format("{0} {1}", firstWord, secondWord);
Console.WriteLine(combination.ToString());

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

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.

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.

Categories

Resources