Assert Variable is not Null - c#

I have a Variable with type DateTime?
In a Function I check it for being null and want to use it afterwards without always having to ?. every call. In e.g. Kotlin the IDE recognizes a check like that and asserts that the variable cannot be null afterwards. Is there a way to do this in C#?
DateTime? BFreigabe = getDateTime();
if (BFreigabe == null) return false;
TimeSpan span = BFreigabe - DateTime.Now;
//Shows Error because it.BFreigabe has the type DateTime?, even though it can't be null
Edit:
When using
TimeSpan span = BFreigabe.Value - DateTime.Now;
instead it works in this case because .Value doesn't have nullsafety at all. However, considering that this would compile even without the null check and just produce an error, the general question still remains. How can one persuade C# that a former nullable variable isn't nullable any more?
Edit 2
Casting DateTime on the Variable works.
TimeSpan span = (DateTime)BFreigabe - DateTime.Now;
Still not as safe as in Kotlin, but similar enough.

If you have the previous check, you can access the value. Nullable types always have two properties: HasValue and Value.
You could either cast to DateTime (Without the ?) or use the value property.
DateTime? BFreigabe = getDateTime();
if (!BFreigabe.HasValue == null)
return false;
TimeSpan span = BFreigabe.Value - DateTime.Now;
Or store the nullable variable in a non nullable variable:
DateTime? BFreigabe = getDateTime();
if (BFreigabe.HasValue == null)
{
DateTime neverNull = BFreigabe.Value;
TimeSpan span = neverNull - DateTime.Now;
}
This will get full editor support and guarantee that there is no NullReferenceExcpetion.
EDIT: Because your question states Assert. Assert usually means that we will throw an exception if the state is invalid.
In this case, omit the check for nullness. If you access var.Value while var is null, this will throw a NullReferenceException. This moves the responsibility to the caller.
Another option would be to not use the nullable variable. Either by converting it (see the second listing) or by not accepting Nullable types as a parameter.
function TimeSpan Calc(DateTime time)
{
// here we know for sure, that time is never null
}

How about this?
DateTime? BFreigabe = getDateTime();
if (!BFreigabe.HasValue) return false;
DateTime BFreigabeValue = BFreigabe.Value;
TimeSpan span = BFreigabeValue - DateTime.Now;

Try to convert NULL value to any value, that is irrelevant.
DateTime? BFreigabe = getDateTime();
if (BFreigabe == null) return false;
TimeSpan span = (BFreigabe??DateTime.Now) - DateTime.Now;

Related

csharp Value of '01/01/0001 00:00:00' is not valid how to handle?

if (File.Exists(settingsFile))
{
string[] lines = File.ReadAllLines(settingsFile);
if (lines.Length > 0)
{
trackBarHours.Value = Convert.ToInt32(optionsfile.GetKey("trackbarhours"));
trackBarMinutes.Value = Convert.ToInt32(optionsfile.GetKey("trackbarminutes"));
trackBarSeconds.Value = Convert.ToInt32(optionsfile.GetKey("trackbarseconds"));
savedMilliseconds = Convert.ToInt32(optionsfile.GetKey("milliseconds"));
dateTimePicker1.Value = Convert.ToDateTime(optionsfile.GetKey("timetargetvalue"));
richTextBox1.Text = optionsfile.GetKey("result");
}
}
because the key "timetargetvalue" is not yet created in the settingsFile because i didn't saved it yet for the first time the value of the key of "timetargetvalue" is '01/01/0001 00:00:00'
in that case that there is no yet the key hwo can i handle the datetime exception ?
dateTimePicker1 is a DateTimePicker control.
the exception is on the line :
dateTimePicker1.Value = Convert.ToDateTime(optionsfile.GetKey("timetargetvalue"));
System.ArgumentOutOfRangeException: 'Value of '01/01/0001 00:00:00' is not valid for 'Value'. 'Value' should be between 'MinDate' and 'MaxDate'.
Parameter name: Value'
what should i check against of so it will not throw the exception ?
DateTimePicker.Value must be above DateTimePicker.MinimumDateTime, which is 'January 1, 1753'.
When you haven't set the timetargetvalue, it will resolve to '01/01/0001 00:00:00', as you have seen, which is too early.
So you need to check the value before assigning it to DateTimePicker.Value.
You can do it like this:
DateTime tempDateTime = Convert.ToDateTime(optionsfile.GetKey("timetargetvalue");
dateTimePicker1.Value = tempDateTime >= DateTimePicker.MinimumDateTime ? tempDateTime : DateTimePicker.MinimumDateTime;
When dealing with a Struct such as DateTime that does not have any value we need to consider that this is not a class and can not be set to null. It must always have some value. (see https://learn.microsoft.com/en-us/dotnet/api/system.datetime?view=net-7.0)
The exception mentions in a round about way that the range of acceptable values is between dateTimePicker1.MinDate and dateTimePicker1.MaxDate so one option is to check if your value is within this range. But it's unlikely to be the best option. (see https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.datetimepicker.mindate?view=windowsdesktop-6.0)
I'm pretty sure that DateTime default value is equal to that of DateTime.Min but if you really wanted to check if the value is default then I would suggest comparing it to default(DateTime) would be better.
This pretty much covers the use of DateTime and value defaults when null is not an option. Which brings up a possibly more desirable option. Encapsulation.
We could instead encapsulate the DateTime struct into a Nullable class. The encapsulating class will be nullable and will also be able to present the encapsulated value through a property called Value. (see https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/nullable-value-types)
There are two ways to declare such a Nullable class, both of which compile to the same thing:
Nullable<DateTime> myNullableDate = null;
DateTime? anotherNullableDate = null;
Since the DateTime is encapsulated in a Nullable object we can start using a null reference check. We can also call a method on Nullable called HasValue which returns a bool (True if it has a value).
EDIT: I notice that you're not doing any checks before trying to parse the DateTime and then directly setting it into the DateTimePicker.Value which can accept a null value. (although setting null won't clear a previously set value).
As such perhaps what you might want to do is handle the scenario a bit better and then use a DateTime.TryParse() instead. (see https://learn.microsoft.com/en-us/dotnet/api/system.datetime.tryparse?view=net-7.0)
e.g. (not the most optimized code, but I think it's easier to follow along in a more verbose form)
private DateTime? LoadDateFromOptions(string key)
{
var rawValue = optionsfile.GetKey(key);
if (!string.IsNullOrEmpty(rawValue))
{
return null;
}
DateTime dateValue;
bool isSuccess = DateTime.TryParse(rawValue, out dateValue);
if (isSuccess)
{
return dateValue;
}
else
{
return null;
}
}
and then instead of having that exception you can load the value optionally a bit more like this:
var timeTarget = LoadDateFromOptions("timetargetvalue");
if (timeTarget != null)
{
dateTimePicker1.Value = timeTarget;
}

Why do ternary operator and if statement return different results? [duplicate]

This question already has answers here:
Nullable DateTime used in property with expression returns unexpected default value
(2 answers)
Closed 1 year ago.
In the following example, I'm returning a DateTimeOffset? using the default value
var a = ConvertToDateTimeOffsetA(null); // 1/1/0001 12:00:00 AM +00:00
var b = ConvertToDateTimeOffsetB(null); // null
private static DateTimeOffset? ConvertToDateTimeOffsetA(DateTime? date)
{
return date != null
? new DateTimeOffset(date.Value, TimeSpan.Zero)
: default;
}
private static DateTimeOffset? ConvertToDateTimeOffsetB(DateTime? date)
{
if (date != null)
return new DateTimeOffset(date.Value, TimeSpan.Zero);
return default;
}
Why is there a difference between the returned output in the ternary compared to the if statement?
My guess would be the ternary first coerces the type to DateTimeOffset and then inline converts back to Nullable<DateTimeOffset>, but I'm not quite sure why?
In the ternary version, it is interpreting your default as default(DateTimeOffset), the other output expression type in the conditional. Then it is interpreting the ternary as a whole as a nullable, which will never be null.
In the second case, your return is using default(DateTimeOffset?), from the declared return type.
In this case, you may want to use an explicit type in the default expression, or: just use the second form and add a comment (and ideally a unit test), so nobody "fixes" it in the future.

Nullable DateTime in C#

I have two questions related to DateTime assingments
DateTime? y = 1 == 1 ? null: DateTime.MaxValue;
DateTime? y = null; // assignment works as expected
Why the first assignment issues error of type conversion between null and DateTime?
Which is the preferred way for null assignments of DateTime? in c#.
DateTime? x = default(DateTime?); //prints null on console
DateTime? x = null; // prints null on console
DateTime? x = DateTime.MinValue; //print 01/01/0001
The second statement DateTime? y = null; is only an assignment of null to a nullable object.
Whereas the first is a conditional assignment, which assigns some value for the true state and some other value for the false; Here you are using the conditional operator for evaluating the condition. according to MSDN first_expression (executes if true) and second_expression*(executes if false)* must be of same type or an implicit conversion must exist from one type to the other. In our case both are different so The simple solution is doing an explicit conversion as like this:
DateTime? y = 1 == 1 ?(DateTime?) null : DateTime.MaxValue;
A1. Because in ternary operator both expressions/results should be of same type.
Acc. to MSDN Either the type of first_expression and second_expression must be the same, or an implicit conversion must exist from one type to the other.
In your question, null and DateTime.MinValue do not match and hence the error conversion between null and DateTime.
You can do
DateTime? y = 1 == 1 ? null : (DateTime?)DateTime.MaxValue;
This way both answers return an answer whose type is DateTime?.
A2. Normally there is no said/preferred way of assigning this. This depends on user convention. All three are good and depend on user requirements.
Because ?: Operator operator expects same type on both sides.
Either the type of first_expression and second_expression must be the same, or an implicit conversion must exist from one type to the other.
So solution will be like below:
DateTime? y = 1 == 1 ? (DateTime?)null : DateTime.MaxValue;
And for second question, this will be good way for null assignment
DateTime? x = null;
DateTime? y = 1 == 1 ? null: DateTime.MaxValue;
This statement is giving an assignment error not because of the null assignment to a variable it is because of using null assignment in ternary operator and as you are using a class type here you the ternary operator do not lead you to do this illegal stuff as per CLR specifications mentioned,It might give you a straight compilation error.
//Which is the preferred way for null assignments of DateTime? in c#.
DateTime? x = default(DateTime?); //prints null on console
DateTime? x = null; // prints null on console
DateTime? x = DateTime.MinValue; //print 01/01/0001
As per Specifications and guidelines provided the Class Types should not be assigned null in any scenario so as per standard you can use the min value(though you can use default value too but it might effect in type conversions when needed)
The second one that you mentioned. You need to cast null value in this time asmensioned by Sir Nikhil Agrawal.
Ternary
int y = 1;
DateTime? dt3 = y == 1 ? (DateTime?)null : DateTime.MinValue;
Traditional way
DateTime? dt3 = null;
if (y == 1)
dt3 = null;
else
dt3 = DateTime.MinValue;
if you want to cast null to nullable datetime then you can use
DateTime? dt = (DateTime?)null;

Allow null DateTime? variable comparison with DateTime variable in C#

I have two variables of type DateTime and DateTime?
DateTime StartDateFromDb;
DateTime? StartDateFromFilter;
if(StartDateFromDb.Date == StartDateFromFilter.Date);
While comparing, .Date is not allowingfor StartDateFromFilter of type allow null
Thanks in advance
Use the Value property available as
if(StartDateFromFilter.HasValue && StartDateFromDb.Date == StartDateFromFilter.Value.Date)
PS: Better to add a null value check. StartDateFromFilter must have a value.(HasValue is true when DateTime? type variable is not null)
For any nullable type , you can use value property.
StartDateFromFilter.Value.Date
In your case , this should work fine
if(StartDateFromDb.Date == StartDateFromFilter.Value.Date)
//// in this case .Date is not allowingfor StartDateFromFilter

How can someone handle default datetime

I have DAL where I convert database null value to their equivalent representation in C#. For example:
NULL for Numeric = 0
NULL for String = String.Empty
NULL for DateTime = "1/1/0001" (i.e. DateTime.MinValue)
The problem, for date, lies in the presentation layer, especially in GridViews. You cannot show 1/1/01 to users.
What I used to do is check if myDate.Year=1 or myDate.Year < AcceptedDate and display empty string, but seems to be extra effort unlike other types
Please am open to better approach. Thanks.
Use Nullable datatype to store null value.
DateTime? value = null;
int? myNullableInt = 1;
value = DateTime.Now;
How to check whether variable has value or null
if (value!=null)
String value can store null, so there is no diffrent datatype for string to store null.
string var;
if (var == null)
or
if (String.IsNullOrEmpty(var))
You can also use DateTime.MinValue constant.
http://msdn.microsoft.com/en-us/library/system.datetime.minvalue.aspx
Your conditions would be:
if (myDate == DateTime.MinValue)
You can use Nullable DateTime, so you will return DateTime? instead of DateTime from your DAL. This way you can check if returned value is null.
DateTime? dateTime = null;
As the others mention, you could use a System::Nullable<DateTime>.
The other approach I've seen is to use a standard DateTime and just use a special value such as DateTime.MinValue. This is useful if you need to honor an existing interface's types and can't change the DateTime to a Nullable<DateTime>.
You can either use a Nullable DateTime as the others suggested, or use this trick:
(To prevent non valid defaults.)
// If dateTime has not been initialize, initialize to Now
// (or to any other legal inital values)
dateTime = ((dateTime != new DateTime()) ? dateTime : DateTime.Now);
This trick is useful if you have to use a non-nullable DateTime and want to provide a default if none. (E.g. you have a non-nullable DateTime column in a DB and want to set the value only if row is new.)
I don't think you have much choice but to make the check like you have been and display accordingly. A nullable type might make things easier for you. Depending on your data, even the numeric should be treated this way. DBNull != 0.

Categories

Resources