Ternary operator error, on valid if: else; statement - c#

I have a valid if: else; code section as follows:
var obj = new Object();
if(Validation.IsDirectory(fileName))
{
obj = Activator.CreateInstance(typeof(FilePath));
}
else
{
obj = Activator.CreateInstance(typeof(FileName));
}
The above generates no error. But, if I translate this to a shorthand if statement, like below:
Validation.IsDirectory(fileName) ? obj = Activator.CreateInstance(typeof(FilePath)) : obj = Activator.CreateInstance(typeof(FileName));
I get the error:
Error CS0201 Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement
In that error documentation it clearly states that:
...Invalid statement is any line or series of lines ending in a
semicolon that does not represent an assignment (=), method call (),
new, -- or ++ operation.
But out of my first 3 statements the first is a method call and the last two are assignment operations.
So, why am I receiving this error? And how do I write this statement as a shorthand if statement?

You cannot make the assignment inside the ternary operator. This operator is used in expressions and yields a value that you then can assign. Also, since now we have a single assignment, we can merge this with the declaration.
(Btw., the initialization expression new Object() in your declaration is superfluous, as the following statements replace this object anyway. object obj; would suffice.)
object obj = Validation.IsDirectory(fileName)
? Activator.CreateInstance(typeof(FilePath))
: Activator.CreateInstance(typeof(FileName));
However, you can simplify this further and call the Activator only once by applying the ternary operator the Type arguments only:
object obj = Activator.CreateInstance(
Validation.IsDirectory(fileName) ? typeof(FilePath) : typeof(FileName)
);
It would be easier to work with FilePath and FileName if they had a common base class that you would use instead of object. The same pattern is used in the System.IO Namespace namespace with the DirectoryInfo Class and the FileInfo Class. Both derive from System.IO.FileSystemInfo and share common members like Name, FullName or Delete().

The ternary conditional operator is not "a shorthand if statement". The ternary operator is an expression which resolves to a value.
In your attempt it would be structurally similar to a line of code which is nothing more than a value:
4;
This line of code is not a statement, hence the error.
You can use the result of the expression as part of a statement. For example:
var x = 4;
Or in your case:
var x = someTernaryExpression;
Which would be:
var obj = Validation.IsDirectory(fileName) ? Activator.CreateInstance(typeof(FilePath)) : Activator.CreateInstance(typeof(FileName));
In short...
When you want to conditionally perform an operation, use if.
When you want to conditionally resolve to a value inline, use ?:.

You perform the assignment as a result of (i.e. after) the ternary operator
obj = Validation.IsDirectory(fileName) ? Activator.CreateInstance(typeof(FilePath)) : Activator.CreateInstance(typeof(FileName));
The ternary operator does the check and returns the first value when true, otherwise it returns the second value.
The returned value can then be assigned normally.

Related

Can't use ternary for return null

I want replicate this condition:
string responseText = getData();
if(responseText == null){ return; }
with the ternary operator, what I tried is:
responseText == null ? return : null;
but I get return underlined in red with:
return is not a valid term for the expression.
Essentially I want stop the code of this function with a return if responseText is null, instead if is different against null I need to continue my code. What I did wrong?
Ternary operator is used for assignment:
string a = isEmpty ? item : null; //this is OK
If you assign nothing, you cannot use the ternary operation.
response == null ? return : null; //what is this??
What you have done, is likely already correct:
if (responseText == null)
return;
//do something else when text is not null
The purpose of a ternary operator is to be able to create an expression that uses conditions.
It's not intended for controlling the flow of your program, and you shouldn't attempt to use it that way.
Stick with your if statement.
The ternary operator is an expression - it returns one value or the other based on the condition. You are trying to use it for program flow which is not possible.
I see nothing wrong with your if statement - is it clear, concise, and most importantly, it works.
You can't return return. The returned value must be a variable of the same type as the one receiving the ternary expression's result.
The ternary operator evaluates an expression. It cannot control the flow of your program. Your best bet is to use an old fashioned if statement, such as the one you provided in your question.
The operand of a ternary operator should be a expression yielding a value. But in this case return doesn't yields any value.

?: Operator return void

I want to use the ?: operator intstead of if else
e.g.
var directory = new DirectoryInfo(path);
if (!directory.Exist())
{
directory.Create();
}
else
{
// do nothing
}
I tried to use ?: like this:
var directory = new DirectoryInfo(path);
!directory.Exist() ? directory.Create() : void;
but it says "Invalid expression term void", null also isn't working.
Can anyone tell me a solution?
In you scenario, only having a if condition is better suited.
Just for your understanding, A ternary Operator (?:) needs to result into a value in the right side and also needs a variable in left side to assign the result value e.g.:
x = (y== null) ? 0: 1;
This means assign 0 to x when y is null otherwise assign 1.
So in your example/scenario, you may write something like this to result into a directory creation status as below:
var newDirectoryCreated = (!directory.Exist()) ? directory.Create() : false;
This way, if new directory is created then newDirectoryCreated will assigned with true otherwise false.
Simply keep the if statement and remove the else clase since you aren't doing anything in there.
You're trying to use the ternary operator which, by definition, must return a value.
From the documentation:
The conditional operator (?:) returns one of two values depending on the value of a Boolean expression.
If your just looking for brevity, you could try this instead:
if (!directory.Exist())
directory.Create();
Ternary operator are not designed to replace if/else They are to simplify assignment and declaration. It should be able to assign the result the statement to something like variable or function. There major use are in assignment or reading.
Something like
var status = !directory.Exist() ? directory.Create() : false;
The correct solution would be to stick to native if condition. The following is enough:
var directory = new DirectoryInfo(path);
if (!directory.Exist())
{
directory.Create();
}
The ?: operator's behavior is roughly this:
for x ? y : z, it will return y if x is true, and otherwise it will return z.
From this we can deduce a couple of things:
both y and z must return something (it won't work if either of them evaluate to void), and
y and z must evaluate to the same type. (Imagine you had something like this: var r = x ? y : z;. Which type is r? Is it the type of y or z? We don't know which of them will be returned, but we have to pick a type at compile-time. So they have to return the same type.
In your case, both evaluate to void, which doesn't work. (And if you changed the last part to null, as you said you'd tried, then they evaluate to different types, one of which is void, which breaks both rules)
The conditional operator (?:) musts return one of two values depending on the value of a Boolean expression. So you can stick with if clause instead, it is still simple to understand rather than conditional operator:
var directory = new DirectoryInfo(path);
if (!directory.Exist()) directory.Create();
The ?: operator is an extention of the if-then-else construction.
The extention is in the then-block and the else-block. Where the then-block and the else-block return void for the if-then-else construciton it must return a type for the ?: operator. An aditional constraint for the types in the ?: operator is that the two types must be identical. This constraint is softened a bit by the fact that automatic casting will be used by the compiler to make the two types identical.
Code using ?: operators is in general shorter but also harder to read. This is one point to consider when replacing the if-then-else construct with the ?: operator. Unless your then-block and else-block are one liners it seldom is worth replacing it with the ?: operator.
The if-then construction is a limited version of the if-then-else construction (or visa versa, the if-then-else construction is an extention of the if-then construction). Since the if-then construction has only one code block, the then-block, it is not possible to replace the if-then construction with the ?: operator. You first have to extend the if-then construct with an empty else-block.
Examples:
// initialising an integer with an if-then construct.
int x = 0;
if (some_condition)
{
x = 1;
}
Think of this as if the then-blockreturns an integer.
It is not possible to use the ?: operator strait away.
// initialising an integer with an if-then-else construct.
int y;
if (some_condition)
{
y = 1;
}
else
{
y = 0;
}
Extended the if-then construct to a if-then-else construct and think of the then-block and else-block as returning a integer for witch the types coincidently ;-) match with each other.
It is possible to use the ?: operator in this case.
// initialising an integer with a ?: operator.
int z = (some_condition) ? 1 : 0;
About your code:
var directory = new DirectoryInfo(path);
if (!directory.Exist())
{
directory.Create();
}
In this case I do not see a sensible way to make the then-block returning a value. That makes using the ?: operator impossible or highly complicated with ugly code as a result. My advise, stick to the if-then construct in this case.

Only assignment, call, increment, decrement, and new object expressions can be used as a statement

I am getting this error in condiotional operator.
string remarks="";
AddDgvNew[6, i].Value==null?remarks="":remarks=AddDgvNew[6,i].Value.ToString();
Yes - because you're not doing anything with the result of the conditional expression. You've got a conditional expression which is trying to be a whole statement. In a simpler version:
bool condition = true;
int x = 10;
int y = 5;
// This is invalid
condition ? x : y;
What did you want to do with the result of the conditional expression? If the point was to assign it to a variable, then you need to do that. Currently you have two separate statements: one declares remarks and assigns it a value; the second is just the conditional expression.
If you're trying to do something else, you'll need to clarify what you're looking for.
Use
string remarks = AddDgvNew[6, i].Value==null?"":AddDgvNew[6,i].Value.ToString();

Ternary Operator in C#

Can anyone please explain to me what happens behind the scenes when you use ternary operator?
does this line of code:
string str = 1 == 1 ? "abc" : "def";
is generated as a simple if / else statement?
Consider the following:
class A
{
}
class B : A
{
}
class C : A
{
}
Now using ternary expression as follows:
A a1 = 1 == 1 ? new B() : new C();
this doesn't even compile with this error:
Type of conditional expression cannot be determined because there is no implicit conversion between 'ConsoleApp1.B' and 'ConsoleApp2.C'
Can anyone shed light on this one?
The type of the conditional operator expression is required to be either the type of the second operand or the type of the third operand. So one of those must be convertible to the other.
In your case, they're not convertible to each other - but both convertible to a third type (A). That isn't considered by the compiler, but you can force it:
A a1 = 1 == 1 ? new B() : (A) new C();
or
A a1 = 1 == 1 ? (A) new B() : new C();
See section 7.14 of the C# 4 spec for more details.
An extract from msdn ?Operator
If condition is true, first expression is evaluated and becomes the result;
if false, the second expression is evaluated and becomes the result.
Only one of two expressions is ever evaluated.
Its pretty explicit.
And your error is pretty explicit too, you are trying to assign a B to a C ... But no cast is available, so error ... Pretty simple
The conditional operator will effectively use the type of the first expression for the second according to whether there is a conversion - and doesn't take into account bases (otherwise it would just always go to object allowing this: ? "hello" : 10).
In this case, the compiler is correct - there is no conversion between the two types. Add a cast, however on the first one - and it'll compile - (A)new B().
Its pretty explicit.
And your error is pretty explicit too, you are trying to assign a B to
a C ... But no cast is available, so error ... Pretty simple
Not relevant at all.
B and C derives from A.
The expression is:
A a1 = 1 == 1 ? new B() : new C();
Both expressions return type that derives from A
Just the compiler looks at the expressions of the ?: operator, and don't care what is the type of variable a1 (left side of the expression)...
The reason for such implementation is very interesting...

C# Should "as string" work like this?

as string caused me a problem when dealing with object arrays. The values after execution are shown in the comments. Should it work this way?
object[] array = new object[2];
array[0] = 0.33;
array[1] = "0.33";
string a = array[0] as string; // a == null !!!??????
string b = array[1] as string; // b == "0.33"
string a2 = array[0] == null ? "" : array[0].ToString(); // a2 == "0.33"
string a3 = Convert.ToString(array[0]); // a3 == "0.33"
Yes, it should.
as is a cast operator.
It can only be used to cast an object to a type that it actually is (or a superclass thereof).
x as Y returns null if x isn't a Y.
the as-operator returns null when it fails to cast an object to the specified type. in this case it failed to cast 0.33 to type string, so string a is null.
MSDN:
The as operator is like a cast operation. However, if the conversion
is not possible, as returns null instead of raising an exception
So yes, the behaviour you are observing is correct.
The as operator is a casting operation, not a conversion operation, so it will only produce the value is the same type, or a super- or sub-class or the type you are trying to cast to.
(Unlike a regular cast, the as operator also does not perform user-defined conversions using the operator keyword.)
"as string" is not a synonym for "ToString()". You are using the "as" operator, and happened to pass it string as a type.
Definition of the as operator:
Remarks
The as operator is like a cast except that it yields null on conversion failure instead of raising an exception. More formally, an expression of the form:
expression as type
is equivalent to:
expression is type ? (type)expression : (type)null
The 'as' operator is basically like casting into a System.Type however the only difference is that it returns a null value if the cast fails instead of throwing an exception.
Check out this link for more info
http://msdn.microsoft.com/en-us/library/cscsdfbt(v=vs.71).aspx
array[0] is a double and cannot be casted to string, hence null.
Call ToString(), most types override it to return something meaningful.

Categories

Resources