C# - checking if a variable is initialized - c#

I want to check if a variable is initialized at run time, programmatically. To make the reasons for this less mysterious, please see the following incomplete code:
string s;
if (someCondition) s = someValue;
if (someOtherCondition) s = someOtherValue;
bool sIsUninitialized = /* assign value correctly */;
if (!sIsUninitialized) Console.WriteLine(s) else throw new Exception("Please initialize s.");
And complete the relevant bit.
One hacky solution is to initialize s with a default value:
string s = "zanzibar";
And then check if it changed:
bool sIsUninitialized = s == "zanzibar";
However, what if someValue or someOtherValue happen to be "zanzibar" as well? Then I have a bug. Any better way?

Code won't even compile if the compiler knows a variable hasn't been initialized.
string s;
if (condition) s = "test";
// compiler error here: use of unassigned local variable 's'
if (s == null) Console.Writeline("uninitialized");
In other cases you could use the default keyword if a variable may not have been initialized. For example, in the following case:
class X
{
private string s;
public void Y()
{
Console.WriteLine(s == default(string)); // this evaluates to true
}
}
The documentation states that default(T) will give null for reference types, and 0 for value types. So as pointed out in the comments, this is really just the same as checking for null.
This all obscures the fact that you should really initialize variables, to null or whatever, when they are first declared.

With C# 2.0, you have the Nullable operator that allows you to set an initial value of null for heretofore value types, allowing for such things as:
int? x = null;
if (x.HasValue)
{
Console.WriteLine("Value for x: " + num.Value);
}
Which yields:
"Value for x: Null".

Just assign it null by default, not a string value

Here's one way:
string s;
if (someCondition) { s = someValue; }
else if (someOtherCondition) { s = someOtherValue; }
else { throw new Exception("Please initialize s."); }
Console.WriteLine(s)
This might be preferable for checking if the string is null, because maybe someValue is a method that can sometimes return null. In other words, maybe null is a legitimate value to initialize the string to.
Personally I like this better than an isInitialized flag. Why introduce an extra flag variable unless you have to? I don't think it is more readable.

You can keep a separate flag that indicates that the string has been initialized:
string s = null;
bool init = false;
if (conditionOne) {
s = someValueOne;
init = true;
}
if (conditionTwo) {
s = someValueTwo;
init = true;
}
if (!init) {
...
}
This will take care of situations when s is assigned, including the cases when it is assigned null, empty string, or "zanzibar".
Another solution is to make a static string to denote "uninitialized" value, and use Object.ReferenceEquals instead of == to check if it has changed. However, the bool variable approach expresses your intent a lot more explicitly.

I would agree with Vytalyi that a default value of null should be used when possible, however, not all types (like int) are nullable. You could allocate the variable as a nullable type as explained by David W, but this could break a lot of code in a large codebase due to having to refine the nullable type to its primitive type before access.
This generic method extension should help for those who deal with large codebases where major design decisions were already made by a predecessor:
public static bool IsDefault<T>(this T value)
=> ((object) value == (object) default(T));
If you are staring from scratch, just take advantage of nullable types and initialize it as null; that C# feature was implemented for a reason.

I pick initialization values that can never be used, typical values include String.Empty, null, -1, and a 256 character random string generator .

In general, assign the default to be null or String.Empty. For situations where you cannot use those "empty" values, define a constant to represent your application-specific uninitialized value:
const string UninitializedString = "zanzibar";
Then reference that value whenever you want to initialize or test for initialization:
string foo = UnininitializedString;
if (foo == UninitiaizedString) {
// Do something
}
Remember that strings are immutable constants in C# so there is really only one instance of UninitializedString (which is why the comparison works).

Related

Dictionary.TryGetValue and possible 'null' warning

I can't seem to wrap my head around the compiler's warning in this case:
using System;
using System.Collections.Generic;
#nullable enable
public class Program
{
public static void Main()
{
Guid guid = Guid.NewGuid();
Dictionary<Guid, string> d = new();
bool found = d.TryGetValue(guid, out string? str);
if (found is false)
{
return;
}
string s = str; // WARNING: possible null value
}
}
After all, I'm doing the found check and return if there is no value (e.g. when the out str value is null). Plus, the out parameter of the .TryGetValue method is annotated with [MaybeNullWhen(false)].
Would appreciate your help figuring our where I'm wrong in my expectations and fixing the code, thanks. Code is here.
Basically the compiler (or language specification) isn't "smart" enough to carry the conditional processing of the return value from TryGetValue over when you use a local variable.
If you inline the TryGetValue call into the if condition, it's fine:
if (!d.TryGetValue(guid, out string? str))
{
return;
}
string s = str; // No warning
It's possible that over time this will evolve to be more sophisticated, but it's relatively difficult to specify this sort of thing in a bullet-proof way.
This isn't limited to nullable reference types - there are other cases where logically code is fine from a human perspective, but the compiler will reject it. For example:
string text;
bool condition = DateTime.UtcNow.Hour == 5;
if (condition)
{
text = "hello";
}
if (condition)
{
Console.WriteLine(text); // Error: use of unassigned local variable
}
We know that if we get into the second if statement body, we'll also have gone into the first one so text will have been assigned a value, but the rules of the compiler don't attempt to be smart enough to spot that.

Local variable might not be initialized before accessing - after calling .TryParse()

I have this piece of code:
var kv = new Dictionary<int, string>() { ... };
var kv30Valid = kv.ContainsKey(30) && int.TryParse(kv[30], out var kv30Value);
myObject.nullableInt = kv30Valid ? (int?)kv30Value : null;
Note: myObject is a POCO class representing a table row, that's why nullable int.
I cannot compile my code because I get compiler error on the last line:
Local variable 'kv30Value' might not be initialized before accessing
In which case can it be unintialized and how to properly handle the case to allow valid code?
I need to populate the myObject properties with values from the kv (if they are present) parsed to their respective values.
Solution:
Moving the condition into TryParse() method solved the problem.
var kv30Valid = int.TryParse(kv.ContainsKey(30) ? kv[30] : null, out var kv30Value);
The definite assignment analyzer has limitations (as it must, yada yada yada halting problem, etc). Although we can look at this code and conclude that it'll only access kv30value if ContainsKey returned true and thus TryParse was called, it's too "separate" for the analyzer to be able to see this.
If this was inside an if block using kv30valid it might be able to see it but even then I'm not sure.
In which case can it be unintialized
When kv.ContainsKey(30) returns false, int.TryParse() isn't called, and kv30Value won't be assigned.
To simplify the issue, you have an unassigned variable:
bool test; // declared, but not assigned
if (test)
{
Console.WriteLine("Test is true");
}
This won't compile, because test is not assigned.
Now a method with an out parameter will definitely assign the variable:
bool test;
Assign(out test);
if (test)
{
Console.WriteLine("Test is true");
}
private static void Assign(out bool foo)
{
foo = true;
}
This will print "Test is true".
Now if you make the assignment conditional:
bool test;
bool condition = DateTime.Now > DateTime.Now;
if (condition)
{
Assign(out test);
}
if (test) { ... }
You'll be back at the compiler error:
CS0165: Use of unassigned local variable test
Because the assignment of test can't be guaranteed by the compiler, so it forbids further use of that variable.
Even if the usage of the variable uses the same condition:
bool test;
bool condition = DateTime.Now > DateTime.Now;
if (condition)
{
Assign(out test);
}
if (condition && test)
{
Console.WriteLine("Test is true");
}
Then still the compiler refuses you to use test.
That's exactly the same as with your && int.TryParse(..., out) code. The right side of the && is conditionally executed, thus the compiler will refuse to let you use the variable that's potentially unassigned.
Regarding the discussion below and the downvote on my answer, if you want to know the why behind all this, see the C# language specification chapter 5.3 Definite assignment. Basically put, you get this error because the compiler does a best effort attempt at statically analyzing whether the variable is assigned.
how to properly handle the case to allow valid code?
Declare it above, and assign it a sensible default value:
int kv30Value = 0;
var kv30Valid = kv.ContainsKey(30) && int.TryParse(kv[30], out kv30Value);
Or simplify the code by moving it into an if, where it'll be definitely assigned:
if (kv.ContainsKey(30) && int.TryParse(kv[30], out var kv30Value))
{
myObject.nullableInt = kv30Value;
}

ASP.NET C# Bool type casting

This code throwing out an error:
bool status1 = (bool)Cache["cache_req_head"];
bool status2 = (bool)Cache["cache_super"];
bool status3 = (bool)Cache["cache_head"];
This is how the cache variables were set:
if (checkreqhead == true)
{
Cache["cache_req_head"] = true;
}
else if (checksuper == true)
{
Cache["cache_super"] = true;
}
else if (checkhead == true)
{
Cache["cache_head"] = true;
}
Coming from PHP background, this is awkward. The error is:
Object reference not set to an instance of an object
I'm certain it is something really simple, but probably I can't spot it.
THANKS ALL FOR HELPING :)
"Object reference not set to an instance of an object" is c# lingo for "you did something stupid with a null value"
If the Cache is empty you need to check that first
bool status1 = (bool)Cache["cache_req_head"];
should be
bool status1 = false;
if (Cache["cache_req_head"] != null)
{
status1 = (bool)Cache["cache_req_head"];
}
This is an effect of the fact that value types (like bool, int, etc) in c# can not be null. There is a wrapper, Nullable<T> with the shorthand T? that you can use if you want to allow null values for the value types.
You can cast your value to a bool? since that allows for null.
bool? status1 = (bool?)Cache["cache_req_head"];
You can then check status1 == null or status1.HasValue, to get the actual bool value you need to pick it out with status1.Value. If you pick status1.Value while status1 == null you will get a runtime exception like the one you just got.
Actually, the best way to check for whether a value exists or not in Cache is by doing:
//string is used as an example; you should put the type you expect
string variable = Cache["KEY"] as string;
if(variable!=null)
{
// do something
}
The reason why doing if(Cache["KEY"]!=null) myVariable=Cache["Key"]; is unsafe, is because the object stored in Cache["Key"] may be removed from Cache before you get a chance to assign it to myVariable and you end up thinking that myVariable holds a non-null value.
You obviously only setting one of the cache entries at a time. So unless you run the "setter" code 3 times with only 1 variable set to true, then you always going to have nulls returned.
null does not cast into bool because its a value type. Try using bool?
Since Cache[] returns an object, which is null if not set, then you're getting an exception trying to cast null into a bool.
You'd have to check if that key exists first, or you'd have to set each key to "false" as a default.

A property or indexer may not be passed as an out or ref parameter

I'm getting the above error and unable to resolve it.
I googled a bit but can't get rid of it.
Scenario:
I have class BudgetAllocate whose property is budget which is of double type.
In my dataAccessLayer,
In one of my classes I am trying to do this:
double.TryParse(objReader[i].ToString(), out bd.Budget);
Which is throwing this error:
Property or indexer may not be passed as an out or ref parameter at
compile time.
I even tried this:
double.TryParse(objReader[i].ToString().Equals(DBNull.Value) ? "" : objReader[i].ToString(), out bd.Budget);
Everything else is working fine and references between layers are present.
Others have given you the solution, but as to why this is necessary: a property is just syntactic sugar for a method.
For example, when you declare a property called Name with a getter and setter, under the hood the compiler actually generates methods called get_Name() and set_Name(value). Then, when you read from and write to this property, the compiler translates these operations into calls to those generated methods.
When you consider this, it becomes obvious why you can't pass a property as an output parameter - you would actually be passing a reference to a method, rather than a reference to an object a variable, which is what an output parameter expects.
A similar case exists for indexers.
This is a case of a leaky abstraction. A property is actually a method, the get and set accessors for an indexer get compiled to get_Index() and set_Index methods. The compiler does a terrific job hiding that fact, it automatically translates an assignment to a property to the corresponding set_Xxx() method for example.
But this goes belly up when you pass a method parameter by reference. That requires the JIT compiler to pass a pointer to the memory location of the passed argument. Problem is, there isn't one, assigning the value of a property requires calling the setter method. The called method cannot tell the difference between a passed variable vs a passed property and can thus not know whether a method call is required.
Notable is that this actually works in VB.NET. For example:
Class Example
Public Property Prop As Integer
Public Sub Test(ByRef arg As Integer)
arg = 42
End Sub
Public Sub Run()
Test(Prop) '' No problem
End Sub
End Class
The VB.NET compiler solves this by automatically generating this code for the Run method, expressed in C#:
int temp = Prop;
Test(ref temp);
Prop = temp;
Which is the workaround you can use as well. Not quite sure why the C# team didn't use the same approach. Possibly because they didn't want to hide the potentially expensive getter and setter calls. Or the completely undiagnosable behavior you'll get when the setter has side-effects that change the property value, they'll disappear after the assignment. Classic difference between C# and VB.NET, C# is "no surprises", VB.NET is "make it work if you can".
you cannot use
double.TryParse(objReader[i].ToString(), out bd.Budget);
replace bd.Budget with some variable.
double k;
double.TryParse(objReader[i].ToString(), out k);
Possibly of interest - you could write your own:
//double.TryParse(, out bd.Budget);
bool result = TryParse(s, value => bd.Budget = value);
}
public bool TryParse(string s, Action<double> setValue)
{
double value;
var result = double.TryParse(s, out value);
if (result) setValue(value);
return result;
}
Place the out parameter into a local variable and then set the variable into bd.Budget:
double tempVar = 0.0;
if (double.TryParse(objReader[i].ToString(), out tempVar))
{
bd.Budget = tempVar;
}
Update: Straight from MSDN:
Properties are not variables and
therefore cannot be passed as out
parameters.
This is a very old post, but I'm ammending the accepted, because there is an even more convienient way of doing this which I didn't know.
It's called inline declaration and might have always been available (as in using statements) or it might have been added with C#6.0 or C#7.0 for such cases, not sure, but works like a charm anyway:
Inetad of this
double temp;
double.TryParse(objReader[i].ToString(), out temp);
bd.Budget = temp;
use this:
double.TryParse(objReader[i].ToString(), out double temp);
bd.Budget = temp;
So Budget is a property, correct?
Rather first set it to a local variable, and then set the property value to that.
double t = 0;
double.TryParse(objReader[i].ToString(), out t);
bd.Budget = t;
Usually when I'm trying to do this it's because I want to set my property or leave it at the default value. With the help of this answer and dynamic types we can easily create a string extension method to keep it one lined and simple.
public static dynamic ParseAny(this string text, Type type)
{
var converter = TypeDescriptor.GetConverter(type);
if (converter != null && converter.IsValid(text))
return converter.ConvertFromString(text);
else
return Activator.CreateInstance(type);
}
Use like so;
bd.Budget = objReader[i].ToString().ParseAny(typeof(double));
// Examples
int intTest = "1234".ParseAny(typeof(int)); // Result: 1234
double doubleTest = "12.34".ParseAny(typeof(double)); // Result: 12.34
decimal pass = "12.34".ParseAny(typeof(decimal)); // Result: 12.34
decimal fail = "abc".ParseAny(typeof(decimal)); // Result: 0
string nullStr = null;
decimal failedNull = nullStr.ParseAny(typeof(decimal)); // Result: 0
Optional
On a side note, if that's an SQLDataReader you may also make use of GetSafeString extension(s) to avoid null exceptions from the reader.
public static string GetSafeString(this SqlDataReader reader, int colIndex)
{
if (!reader.IsDBNull(colIndex))
return reader.GetString(colIndex);
return string.Empty;
}
public static string GetSafeString(this SqlDataReader reader, string colName)
{
int colIndex = reader.GetOrdinal(colName);
if (!reader.IsDBNull(colIndex))
return reader.GetString(colIndex);
return string.Empty;
}
Use like so;
bd.Budget = objReader.GetSafeString(i).ParseAny(typeof(double));
bd.Budget = objReader.GetSafeString("ColumnName").ParseAny(typeof(double));
I had the same problem (5 minutes ago) and I solved it using old style properties with getter and setter, whose use variables.
My code:
public List<int> bigField = new List<int>();
public List<int> BigField { get { return bigField; } set { bigField = value; } }
So, I just used bigField variable. I'm not the programmer, if I misunderstood the question, I'm really sorry.

What is the purpose of a question mark after a value type (for example: int? myVariable)?

Typically the main use of the question mark is for the conditional, x ? "yes" : "no".
But I have seen another use for it but can't find an explanation of this use of the ? operator, for example.
public int? myProperty
{
get;
set;
}
It means that the value type in question is a nullable type
Nullable types are instances of the System.Nullable struct. A
nullable type can represent the correct range of values for its
underlying value type, plus an additional null value. For example, a
Nullable<Int32>, pronounced "Nullable of Int32," can be assigned any
value from -2147483648 to 2147483647, or it can be assigned the null
value. A Nullable<bool> can be assigned the values true, false, or
null. The ability to assign null to numeric and Boolean types is
especially useful when you are dealing with databases and other data
types that contain elements that may not be assigned a value. For
example, a Boolean field in a database can store the values true or
false, or it may be undefined.
class NullableExample
{
static void Main()
{
int? num = null;
// Is the HasValue property true?
if (num.HasValue)
{
System.Console.WriteLine("num = " + num.Value);
}
else
{
System.Console.WriteLine("num = Null");
}
// y is set to zero
int y = num.GetValueOrDefault();
// num.Value throws an InvalidOperationException if num.HasValue is false
try
{
y = num.Value;
}
catch (System.InvalidOperationException e)
{
System.Console.WriteLine(e.Message);
}
}
}
It is a shorthand for Nullable<int>. Nullable<T> is used to allow a value type to be set to null. Value types usually cannot be null.
In
x ? "yes" : "no"
the ? declares an if sentence. Here: x represents the boolean condition; The part before the : is the then sentence and the part after is the else sentence.
In, for example,
int?
the ? declares a nullable type, and means that the type before it may have a null value.
it declares that the type is nullable.
practical usage:
public string someFunctionThatMayBeCalledWithNullAndReturnsString(int? value)
{
if (value == null)
{
return "bad value";
}
return someFunctionThatHandlesIntAndReturnsString(value);
}
int? is shorthand for Nullable<int>. The two forms are interchangeable.
Nullable<T> is an operator that you can use with a value type T to make it accept null.
In case you don't know it: value types are types that accepts values as int, bool, char etc...
They can't accept references to values: they would generate a compile-time error if you assign them a null, as opposed to reference types, which can obviously accept it.
Why would you need that?
Because sometimes your value type variables could receive null references returned by something that didn't work very well, like a missing or undefined variable returned from a database.
I suggest you to read the Microsoft Documentation because it covers the subject quite well.
Means that the variable declared with (int?) is nullable
int i1=1; //ok
int i2=null; //not ok
int? i3=1; //ok
int? i4=null; //ok
To add on to the answers above, here is a code sample
struct Test
{
int something;
}
struct NullableTest
{
int something;
}
class Example
{
public void Demo()
{
Test t = new Test();
t = null;
NullableTest? t2 = new NullableTest();
t2 = null;
}
}
This would give a compilation error:
Error 12 Cannot convert null to 'Test' because it is a non-nullable
value type
Notice that there is no compilation error for NullableTest. (note the ? in the declaration of t2)
To add on to the other answers:
Starting in C# 8.0, Nullable<> and ? are NOT always interchangeable. Nullable<> only works with Value types, whereas ? works with both Reference and Value types.
These can be seen here in the documentation
"A nullable reference type is noted using the same syntax as nullable
value types: a ? is appended to the type of the variable."
And here
public struct Nullable<T> where T : struct

Categories

Resources