Differences in null declaration - c#

Take the following:
obj myVar;
and
obj myVar = null;
Is there an actual difference between these two - and are they both caught by (myVar == null)?

Your answer is in your question. obj != null means "the object exists".
However, this is only true almost all the time. A custom override of the == and != operator can change this functionality, so to be absolutely sure you can use !Object.ReferenceEquals(obj,null) to ensure that the object does exist, in all cases.
The error you are getting is a System.NullReferenceException, and will always be averted by this check.

The short, but sweet, answer is: the check (object != null) always prevents object not set to an instance

Worth mentioning
If you are reading objects from a database like in the snippet of code below:
private object GetItem(DataSet dataSet1, string tableName, int row, int col) {
object obj = null;
try {
obj = dataSet1.Tables[tableName].Rows[row][col];
} catch (Exception err) {
Console.WriteLine(err.Message);
}
return obj;
}
The returned value could be null (if an exception were caught) or DBNull.Value if dataSet1.Tables[tableName].Rows[row][col] was not set in the database.
If, however, you neglect to initialize object obj as in the example below:
private object Test2(DataSet dataSet1) {
object obj;
try {
obj = dataSet1.Tables[0].Rows[0][0];
} catch (Exception err) {
Console.WriteLine(err.Message);
}
return obj;
}
The code will not compile under Visual Studio.

That is the same thing. If an object is not set to an instance of an object, it will have not have a reference to anything, and will in other words, be null.

Related

Possible null reference after null check

I have a problem resolving this CS8603 warning. Even though there is a null-check for resource variable, null reference is still possible. How come?
Code:
public string GetResource(string resourcePath)
{
var resource = Application.Current.Resources[resourcePath];
if (resource == null)
{
return $"{ResourceError} [{resourcePath}]";
}
// ToDo: CS8603
return resource.ToString();
}
You did correctly check wether resource is null. But even if it is not, ToString() might return null. You can use something like
return resource.ToString() ?? "";

C# lambda null runtime binding

I'm running into an odd scenario that doesn't happen on my PC, but does for a coworkers.
I have this piece of code:
LoaderHelpers.SetStringValue<blah>(this, "x", $"x response in Header",
() => jsonData.x.response[0].value, false);
The problem is that sometimes, "jsonData.x" is null and, for my coworker a 'cannot bind to null at runtime exception' is thrown, but not for me there isn't. I have code to handle the null scenario, but it's like his code never gets to that point and fails at the call level.
jsonData is of type dynamic.
The method code that handles the null scenario:
public static void SetStringValue<T>(IValidate data, string propertyName,
string valuePath, Func<string> value, bool required)
{
if (data.GetType().GetProperty(propertyName) != null)
{
try
{
if (string.IsNullOrEmpty(value()))
{
if (required)
data.DataValidationErrors.Add($"{valuePath} can't be empty");
data.GetType().GetProperty(propertyName).SetValue(data, null);
}
else
{
data.GetType().GetProperty(propertyName).SetValue(data, value());
}
}
catch
{
//property doesn't exist
if (required)
data.DataValidationErrors.Add($"{valuePath} doesn't exist");
data.GetType().GetProperty(propertyName).SetValue(data, null);
}
}
else
{
throw new NullReferenceException($"In {data.GetType()} => SetStringValue. " +
$"Passed property {propertyName}, but property doesn't exist.");
}
}
Again. Works perfect for me, but not for him. I'm completely lost. Maybe I don't understand how the lamba/function parameters work 100%, but I thought it only got evaluated when value() is invoked.
I should also mention that when I debug this code, I can step into the Nuget package and when he hits the same line, he can't. This maybe a useful hint.
If jsonData (or jsonData.x) is null (as it seems to be at this point) it will crash and give you that error every time you call the method value().
You need to check why jsonData.x is null. Maybe it´s a race condition caused by another thread setting this value to null, maybe it´s because a bad jsonData initialization... Can´t say since that code is not here.
There are so many things wrong with your code, i can't resist.
First of all, instead of copy/pasting the same stuff over and over, you might want to use a variable:
var property = data.GetType().GetProperty(propertyName);
Second, you pass a Func<string> and execute it multiple times, why is it even a function then? Yet again, better only evaluate it once and use a variable...
var unwrapped = value();
That would solve the issue, that Roberto Vázquez' answer adresses.
Then you are misusing NullReferenceException, instead rather use a ArgumentException
Next issue, that valuePath is only used in the exception message, that is a poor design to my beliefs.
The generic T parameter isnt even used, so get rid of it.
Last but not least, that catch-block doing the exact thing that could possibily throw the exception again, i cant see any reason why you would do this.
Finnaly this whole thing becomes a little more clear but its still a mess.
public static void SetStringValue(IValidate data, string propertyName,
string valuePath, Func<string> value, bool required)
{
if(data == null)
throw new ArgumentNullException(nameof(data));
var property = data.GetType().GetProperty(propertyName);
if(property == null)
throw new ArgumentException($"In {data.GetType()} => SetStringValue. " +
$"Passed property {propertyName}, but property doesn't exist.");
var unwrapped = value();
try
{
if (string.IsNullOrEmpty(unwrapped))
{
if (required)
data.DataValidationErrors.Add($"{valuePath} can't be empty");
unwrapped = null; // this might be unecessary.
}
property.SetValue(data, unwrapped);
}
catch(Exception e)
{
// This is probably a bad idea.
property.SetValue(data, null);
if (required)
data.DataValidationErrors.Add(Atleast put a better message here. e.Message ...);
}
}

Field is never assigned to, and will always have it's default value null

I'm using the following array in my code (Enrolment is one of my classes)
Enrolment[] enrolment;
I understand that the array is not initialized here, which would make sense for the error. However, the array is initialized in the following block of code.
public void AddStudent(Person studentName)
{
try
{
for (int i = 0; i < enrolment.Length; i++)
{
if (RelevantCourse.CourseCode == null)
{
throw new Exception("This section has not been added to a course.");
}
else if (enrolment.Length == MaxNumberOfStudents)
{
throw new Exception("Cannot add this student to section. Section is full.");
}
}
int currentLength = enrolment.Length;
enrolment[currentLength] = new Enrolment(SectionId, studentName, RelevantCourse.NoOfEvaluations);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
This block of code runs a try-catch block to see if there will be any errors with adding this Enrolment object to the enrolment array. The enrolment array shows an error stating that the "field is never assigned to, and will always have its default value null". When the code is compiled it obviously throws a null reference exception.
Why is its value null? Can someone direct me in the right direction to a solution here?
You have to initialise the array
Enrollment[] enrollments = new Enrollment[{lengthofarray}];
You can't add stuff or get the properties of an uninitialised object that includes arrays

Using Reflection to get the field/property that is being null compared?

How do I know the log the last property that is null?
For example,
var a = "somevalue";
......
......
if(a == null)
{
Log.Error(MethodBase.GetCurrentMethod().Name + "Property : a is null");
//blah blah
}
Like how I use the reflection to get the current method name, there should be some means by which I can log the latest local variables (or a property or fields)
that is being compared ? I use, log4net by the way to log the errors.
1) Is there any method to achieve this or should we manually log it?
2) Is there any custom method that prints the class -> MethodName -> Propertyname(or FieldName) that is null?
Thanks for your time in advance.
As mentioned by #fsimonazzi, "a" would be a local variable.
That being said there is still no way to examine the current compare operation as in MSIL there is no formal concept of an IF block - only conditional jumps.
If you wanted to get really crazy with the reflection, you may be able to find the current executing instruction and look around near that for a variable, but even then, you will not find the name - only a reference - as names are only used prior to compilation.
Either way, reflection is not going to help you here.
Instead, try using Exceptions - specifically ArgumentNullException. This body of code would become:
void doStuff(string param1, int param2)
{
if (param == null)
throw new ArgumentNullException("param1", "param1 must not be null");
if (param2 < 0)
throw new ArgumentOutOfRangeException("param2", "param2 should be non-negative.");
//method body
}
then, when you call the method, you can catch the exception and log it - no matter what it may be.
public static void Main(string[] args)
{
try
{
doStuff(null, 3);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
Tools like FxCop can help make sure that you are properly validating each parameter.
Properties are actually implemented as methods, so reflection could help you there. If, for example, you were validating in a property and wanted to log the position automatically, you could.
private object _cachedObject = null;
public object CachedObject
{
get
{
if (_cachedObject == null)
{
log(MethodBase.GetCurrentMethod().Name, "creating cached object");
_cachedObject = createCachedObject();
}
return _cachedObject;
}
}
The .Net Framework 4.5 also brings with it a new attribute that can be used to replace the MethodBase.GetCurrentMethod().Name construct you are using to get the method name. See [CallerMemberNameAttribute][3].

Return Boolean from a method

I am making a save option in my program that saves the changes to a file. I am using this code to save and get a MessageBox to show the result of the process I am getting an error on this line "Object reference not set to an instance of an object."
SaveFileCheck = StockHandler.SaveChangesToFile();
this is my code
private void Save_Click(object sender, EventArgs e)
{
bool SaveFileCheck = false;
var result = MessageBox.Show("Are you sure you want to Save the changes ?", "My Application",
MessageBoxButtons.YesNo, MessageBoxIcon.Asterisk);
if (result == DialogResult.Yes)
{
SaveFileCheck = StockHandler.SaveChangesToFile();
if (SaveFileCheck)
{
MessageBox.Show("The process was a success");
}
else
{
MessageBox.Show("The process failed please make sure that the file is not been used and try again");
}
//Save the file back
}
}
}
}
public bool SaveChangesToFile()
{
try
{
if (FileName != null)
{
using (StreamWriter Write = new StreamWriter(FileName, false))
{
foreach (Stock s in FileStockList)
{
Write.Write(s.ToString() + "\r\n");
}
}
}
else {
return false;
}
}
catch(IOException ex)
{
return false;
throw new ArgumentException("something went wrong an error" + ex + "is been cought");
}
return true;
}
StockHandler is null.
If StockHandler is not a static class, you need to create an instance of it before you can call methods on it:
var handler = new StockHandler();
SaveFileCheck = handler.SaveChangesToFile();
Or, if StockHandler is a member variable:
StockHandler = new // something
You haven't shown what StockHandler is, or where you're getting it from - but it looks like it's null. You'll need it to be a reference to a valid object. There's not a lot more we can say just from the code you've given.
Note that this has nothing to do with a method returning a bool.
It could be that StockHandler is null, or something in the SaveChangesToFile method is null or invalid.
EDIT
See here:
private StockHelper StockHandler;
StockHandler.SaveChangesToFile(); // = bang :(
You need to initialize the StockHelper instance:
private StockHelper StockHandler = new StockHelper();
StockHandler.SaveChangesToFile(); // = okay :)
I'm assuming that this code doesn't compile, which probably means that StockHandler is null. Otherwise, the error would likely be pointing to the SaveChangesToFile method.
Secondly, you either need to swallow exceptions in the SaveChangesToFile() method (not advisable), or you need to remove the return statement and throw the exception. If you do decide to throw an exception, it should definitely not be an ArgumentException, as it has nothing to do with arguments supplied to the method (or lack thereof).
What is stockhandler -- your SaveChangesToFile method is an instance method -- so have you instantiated a variable 'StockHandler' to an instance of whatever class contains the method SaveChangesToFile();

Categories

Resources