What is this confusing expression "a == b ? value1 : value2"? - c#

I am new to learning C# and Silverlight and have been given some application files by my employer to start learning. I am able to understand most of the logic, methods and syntax used in C# but there is one line which is very confusing to me. I dont have access to my seniors right now to ask them so the logic behind it so I thought I will ask here.
Take a look at this:
In a .xaml.cs file:
List<object> lst = new List<object>();
lst.Add(GP.mpl.A);
lst.Add(GP.mpl.B);
lst.Add(GP.mpl.C);
lst.Add(GP.mpl.StnNo);
In a different .cs file:
public int StnNo = Convert.ToInt32(lst[3].ToString() == string.Empty ? 0 : Convert.ToInt32(lst[3].ToString()));
I understand that StnNo is being received from lst[3] and converted to Integer through
Convert.ToInt32(lst[3].ToString()
But I dont understand this part:
== string.Empty ? 0 : Convert.ToInt32(lst[3].ToString())
Could you tell me what's going on there? I have done multiple searches on google but didn't find anything related. Thanks for any help.

? is a ternary operator.
condition ? first_expression : second_expression;
?: Operator (C# Reference)
So in you example,
public int StnNo = Convert.ToInt32(lst[3].ToString() == string.Empty ? 0 : Convert.ToInt32(lst[3].ToString()));
is equal to
public int StnNo;
if (lst[3].ToString() == string.Empty)
{
StnNo = 0;
}
else
{
StnNo = Convert.ToInt32(lst[3].ToString());
}

This is the conditional, sometimes referred to as ternary, operator.
It takes the form boolean expression ? true value : false value.
In C#, the true value and false value must be of the same type, or one must be implicitly convertible to the other (but not both). Otherwise, you must legally and explicitly cast one or both to a common type.
In your code, you have
int StnNo = Convert.ToInt32(lst[3].ToString() == string.Empty ? 0 : Convert.ToInt32(lst[3].ToString()));
it is producing the functional equivalent of
int temp;
if (lst[3].ToString() == string.Empty)
temp= 0;
else
temp = Convert.ToInt32(lst[3].ToString());
int StnNo = Convert.ToInt32(temp);
You can see the outer Convert.ToInt32 in your code is actually redundant and can be eliminated.
int StnNo = lst[3].ToString() == string.Empty ? 0 : Convert.ToInt32(lst[3].ToString());

That's a very poorly written way of saying "if lst[3] is empty, then use 0, otherwise parse lst[3]" - because as your question illustrates, it's harder to tell what exactly the original developer intended.
To make it more clear, let's dissect it.
lst[3].ToString() == string.Empty means "does the lst[3] evaluate to an empty string?"
? X : Y means "if so, X, otherwise Y.
0 a constant value
Convert.ToInt32(lst[3].ToString()) parses the value as an lst[3] integer.
Finally the whole expression is passed into another Convert.ToInt32, but this is entirely unnecessary because the result of the conditional expression is always an int.
Since you don't have to call Convert.ToInt32 twice, a better way of writing this would be:
public int StnNo =
(lst[3].ToString() == string.Empty
? 0
: Convert.ToInt32(lst[3].ToString()));
An even better way of writing this would be:
int StnNo;
int.TryParse(lst[3], out StnNo);
It's more lines of code, but it's a lot easier to read.

== string.Empty ? 0 : Convert.ToInt32(lst[3].ToString()) is to check that if lst[3] does not contain any value, then 0 will be assigned to StnNo.

Related

Checking for text boxes not null

If I have two text boxes and I want to know if both of their Text properties are null I can do this:
if (string.IsNullOrWhiteSpace(txtNameFirst.Text) &&
string.IsNullOrWhiteSpace(txtNameLast.Text))
{}
That will check if both are null or blank, but is there a way to say if not null or white space? Essentially, the inverse?
Put a ! before the string.IsNullOrWhiteSpace() method call.
if (!string.IsNullOrWhiteSpace(txtNameFirst.Text) &&
!string.IsNullOrWhiteSpace(txtNameLast.Text))
{
// ...
}
There are several ways:
if (!string.IsNullOrWhiteSpace(txtNameFirst.Text) &&
!string.IsNullOrWhiteSpace(txtNameLast.Text))
{}
or
if (string.IsNullOrWhiteSpace(txtNameFirst.Text) == false &&
string.IsNullOrWhiteSpace(txtNameLast.Text) == false)
{}
or
if (txtNameFirst.Text?.Trim().Length > 0 &&
txtNameLast.Text?.Trim().Length > 0)
{}
As everyone else is saying, !string.IsNullOrWhiteSpace() will work for you.
Based on this question I assume you didn't know this, but the logical negation operator ! is a unary operator that negates its operand. It is defined for bool and returns true if and only if its operand is false.
So another example, let's say I want to see if the string The dog barked loudly contains the letter a, I would type string.Contains("a"). However, if I wanted to to make sure it does not contain the letter a, I would type !string.Contains("a").

C# conditional operator - Call method if condition is true else do nothing

C# provides conditional operator (?:) that returns one of two values depending on the value of a Boolean expression. eg
condition ? first_expression : second_expression;
My question is can we use the same syntax to call a method when condition is true? and when condition is false then do nothing
public void Work(int? val)
{
var list = new List<int>();
//ofcourse line below doesn't work
//but is it possible to call method when condition is true and else do nothing
val.HasValue? list.Add(val.value) : else do nothing
}
the ?: has also been referred to as the ternary operator in the past. Ternary, for three. if this, then do this, else do this.
You have two expressions. If this, do this. This is exactly the point of an if statement. You are trying to fit your case into a construct that it isn't designed for. Don't do this.
Use the correct operation for the job:
if(val.HasValue)
{
list.Add(val.value)
}
The C# conditional operator is used to return a different value depending on the evaluation of a condition. It is not meant to be used to to be used the way you are trying to in your question. It should like be used this :
int test = i > 3 ? 0 : 1;
test will then equal 0 if i is less than (or equal to) 3, or test will equal 1 if 3 is greater than 3.
To do what you want you will have to use a regular if statement (which you can still write in one line by the way) :
if (val.HasValue) list.Add(val.value);
The conditional/ternary operator is supposed to return a value and that very specific value must be assigned back to somewhere.
So, in that case you can do that, yes. But, it would lead to bad design.
In a regular case, one would do this:
int x = (a > b) ? a : b;
Now, lets assume AddToList() is your desired method when the condition renders to true and DoRest() is the method you want to invoke if the condition turns out to false.
In the aforementioned case, you'd end up doing something like this:
int result = val.HasValue? AddToList(val.value) : DoRest();
Now you have to rely on result for finding out which one has been called (if you ever need that) and it's not very expressive and doesn't point to proper code design.
If you get a tad more adventurous you'd end up with :
var actionToInvoke = val.HasValue ? (Action)AddToList: (Action)DoRest;
actionToInvoke();
In any case, none of these lead to very readable code.
So, sticking with a simple if(val.HasValue) would be the simplest way to go here.
The way null conditional operator works is you have to return a value for the variable you are assigning it to. So if you would like a string value or something else other than void you can call the method with out any problem. But to call a void method you can use a delegate.
delegate void DelMethod();
void Method() { }
void MethodTwo() { }
private void MyMethod()
{
DelMethod x;
x = condition == true ? (DelMethod)Method : (DelMethod)MethodTwo;
}

how do I convert if else to one line if else?

how do i convert follow code to one line if else
if (data.BaseCompareId == 2)
report.Load(Server.MapPath("~/Content/StimulReports/MonthGroup.mrt"));
else
report.Load(Server.MapPath("~/Content/StimulReports/YearGroup.mrt"));
i try this code but did not work
data.BaseCompareId == 2
? report.Load(Server.MapPath("~/Content/StimulReports/MonthGroup.mrt"))
: report.Load(Server.MapPath("~/Content/StimulReports/YearGroup.mrt"));
Try with this instead :
string path = data.BaseCompareId == 2
? "~/Content/StimulReports/MonthGroup.mrt"
: "~/Content/StimulReports/YearGroup.mrt";
report.Load(Server.MapPath(path));
Since report.Load() returns a void, it wont work.
Edited version :
string s = data.BaseCompareId == 2
? "MonthGroup.mrt"
: "YearGroup.mrt";
report.Load(Server.MapPath("~/Content/StimulReports/" + s));
I am assuming report.Load returns a void, hence it "doesn't work". That said, why are you doing this? The first example is perfectly clear.
If you want are going to use ?: here use it so only the part which is actually different is in the branching statement:
string fileName = (data.BaseCompareId == 2) ? "MonthGroup.mrt" : "YearGroup.mrt";
report.Load(Server.MapPath("~/Content/StimulReports/" + fileName));
If you want to use a ternary operator, you can do:
report.Load(data.BaseCompareId == 2 ? Server.MapPath("~/Content/StimulReports/MonthGroup.mrt") : Server.MapPath("~/Content/StimulReports/YearGroup.mrt"));
Or (better):
report.Load(Server.MapPath(data.BaseCompareId == 2 ? "~/Content/StimulReports/MonthGroup.mrt" : "~/Content/StimulReports/YearGroup.mrt"));
(Or you could further exploit the similarity in the two strings, as #helb's answer does.)
As has already been noted, your way doesn't work because you're trying to replace a conditional statement with a conditional expression, and conditional expressions have to have a value. Since report.Load apparently returns void, a conditional expression of the form cond ? report.Load(...) : report.Load(...) doesn't have a value, ergo it doesn't work.
Each of the ways above will work because the conditional expressions in them have values - in the first case, the value will be of the type returned by Server.MapPath; in the second case, the value will be of type string.
As to whether you should do this: there are arguments to be made either way. The original way has the advantage of being clear and simple, but it does involve some (arguably undesirable) repetition. The latter approach above has the advantage of only saying things once and emphasising the intent of the whole statement (to load a report), but it's arguably slightly less clear than the original, depending on how used people are to seeing conditional expressions. YMMV.
This syntax is just for cases where it returns something. So you could do something like:
var path = (data.BaseCompareId == 2) ? "~/Content/StimulReports/MonthGroup.mrt" : "~/Content/StimulReports/YearGroup.mrt";
report.Load(Server.MapPath(path));
This is the most concise I could get for a one-liner...
report.Load(Server.MapPath(string.Format("~/Content/StimulReports/{0}Group.mrt", data.CompareId == 2 ? "Month" : "Year")));
However, it seems you just want to make things look cleaner.
More abstraction between data calls and the conditional logic.
You might want to consider making them separate methods, perhaps on your report object?
if(data.CompareId == 2)
report.LoadStimulReports(ReportGroup.Month);
else
report.LoadStimulReports(ReportGroup.Year);
Using an enum, extension method, and static method on your report object...
public enum ReportGroup
{
[DescriptionAttribute("~/Content/StimulReports/MonthGroup.mrt")]
Month,
[DescriptionAttribute("~/Content/StimulReports/YearGroup.mrt")]
Year
}
public static T GetAttribute<T>(this Enum e) where T : Attribute
{
System.Reflection.FieldInfo fi = e.GetType().GetField(e.ToString());
object[] o = (object[])fi.GetCustomAttributes(typeof(T), false);
return o.Length > 0 ? (T)o[0] : default(T);
}
public static void LoadStimulReports(ReportGroup reportGroup)
{
report.Load(Server.MapPath(reportGroup.GetAttribute<DescriptionAttribute>().Description));
}
Now you can simply add another item to the enum if you need another report.
[DescriptionAttribute("~/Content/StimulReports/WeekGroup.mrt")]
Week

C# syntax understanding Oracle Connection Project

I have to modify a Visual Studio 2010 C# project that works with Oracle, looking at some code I've found a function that returns a List<> with values loaded from a database stored procedure (cursor)
while (myIDataReader.Read())
{
// OK
myTable.myStringField = myIDataReader["TableStringField"].ToString();
// ¿?
myTable.myIntField =
Convert.ToInt32((myIDataReader["TableIntField"] == DBNull.Value) ? null : myIDataReader["myTableField"]);
}
Everything's ok, just want to know, what conditions are given when assign myTable.myIntField, I know this column is nullable, but I don't get the syntax, if someone can explain I'll be thankful
You are talking about this line?
myTable.myIntField =
Convert.ToInt32((myIDataReader["TableIntField"] == DBNull.Value) ? null : myIDataReader["myTableField"]);
If you break that statement apart, you have a type of conditional, often called the Ternary operator, explained here.
conditional ? if_true_do_this : if_false_do_this
It is really just a different syntax for:
if(conditional) {
if_true_do_this;
} else {
if_false_do_this
}
After that, it simply passes the result to Convert.ToInt32() to turn it from a string into an int.
So that line of code is just a more concise version of this:
if(myIDataReader["TableIntField"] == DBNull.Value)
{
myTable.myIntField = Convert.ToInt32(null);
}
else
{
myTable.myIntField = Convert.ToInt32(myIDataReader["myTableField"]);
}
The syntax above works correctly and it means:
TableIntField could contains a database null.
This is expressed in NET via the DBNull object and its Value field.
The code checks if the TableIntField contains the DBNull.Value via C# ternary operator.
If the checks result in a true condition, a null is used as argument for Convert.ToInt32 and this, according to MSDN documentation, result in a zero value assigned to myTable.myIntField.

Inline conditional c# - next best solution?

It seems the compiler is not going let this syntax fly.
void main()
{
foo(false?0:"");
}
void foo(int i) {return;}
void foo(string s) {return;}
The only other way I can see of fixing this is something as follows:
void bar(object o)
{
if (o is string){//do this}
else{//im an int, do this}
}
Anyone have any better ideas?
You cannot use a method with a void return type in a ternary expression in this way. End of story.
To understand why this is, remember what the ternary operator actually does -- it evaluates to the following:
(condition ? [true value] : [false value])
What this implies is that the following code:
int x = a ? b : c;
Must be rewritable to:
int x;
if (a)
{
x = b;
}
else
{
x = c;
}
The two above are logically identical.
So how would this work with a method with void as its return type?
// Does this make sense?
int x = condition ? foo(s) : foo(i);
// Or this?
if (condition)
{
x = foo(s);
}
else
{
x = foo(i);
}
Clearly, the above is not legal.
That said, others' suggestions would otherwise be valid if only your foo overloads returned a value.
In other words, if your signatures looked like this:
object foo(string s);
object foo(int i);
Then you could do this (you're throwing away the return value, but at least it'll compile):
object o = condition ? foo(0) : foo("");
Anyway, the ol' if/else is your best bet, in this case.
The method call of foo is determined at compile time, so it cannot call a different method (or overload) based on the result of evaluating the condition. Instead, try something like this:
condition ? foo(0) : foo("")
This way, the compiler will succeed in performing overload resolution and will resolve the first call to foo(int) and the second call to foo(string).
EDIT: As noted by other, you cannot use the ?: operator as a statement, nor can you use methods which return void in it. If your actual methods return compatible types, you could do something like:
int result = condition ? foo(0) : foo("");
If not, you must use an if:
if (condition)
foo(0);
else
foo("");
You're example doesn't make a whole lot of sense (the second example doesn't relate to the first).
I think the first example would be fine as:
void main()
{
foo("");
}
Since 0 will never be passed anyway (false is always false) and you can't use the inline conditional operator without an assignment somewhere (which your example is lacking).
As for the second way, that is probably how I would prefer to see it:
void bar(object o)
{
if(o is string) foo(o as string);
else foo((int)o);
}
I wouldn't pass in an object as a parameter. The int will be boxed, which is a little less efficient. Let the compiler figure out which method to call.
If you wrote:
foo(0);
foo("");
The appropriate method would be called. You could also write:
if (condition) {
foo(0);
} else {
foo("");
}
Depending on what you're trying to do (your example is lacking in a little detail).
If you use Inline if expressions in C#, both parts before and after the ":" have to be of the same type. What you are intending would never work.
Even if you like to do something like this:
DateTime? theTime = true ? DateTime.Now : null;
The compiler is not satisfied. In this case you will have to use:
DateTime? theTime = true ? DateTime.Now : default(DateTime?);
The conditional operator needs the true and false part to be of the same type. Which is why it's not compiling.
var x = condition ? 0 : "";
What type should the compiler choose for x? If you really want it to choose object make a cast or you could force it to choose dynamic in which case method overload would still work but you loose type safety. Both are however strong smells.
Having to test the runtime type is usually a design error but with the limited code (that will always have the same result) it's hard to help with a different approach that would require testing on runtime types
This:
foo(false?0:"")
Could be this:
false ? foo(0) : foo("")
Both results of the conditional operator must of the same type (or be implicitly convertible). So foo(false ? 0 : "") won't work because it is trying to return an Int32 and a String. Here's more information on the conditional operator.
The fix I would do is change that line to false ? foo(0) : foo("").
EDIT: Derp, can't use a conditional operator just in the open like that. They can only be used for assignments. You'll have to use a if/else block. Not in one line, but it'll do in a pinch.

Categories

Resources