foreach looping variable throws NullReferenceException but Enumerable is not null - c#

Some people decided to close my previous question, but the question they linked (What is a NullReferenceException, and how do I fix it?) did not have an answer. This question is fundamentally different since the enumerable is populated. It is not null. Just as the first answer stated, I placed "strategic breakpoints" and checked the variables.
I'm debugging a XUnit test and it turns out that in my business logic the iteration variable in the foreach loop is throws an exception "Object Reference not set to instance of object". However, the list over which the iteration is happening is NOT null. I can see that when I'm debugging. Here is the code:
Business logic:
List<string> regionArray = new List<string>();
if (someCondition)
{
regionArray = _utils.GetRegions(someParam); // this is not returning null
}
foreach (var region in regionArray)
{
var query = from dataSet in myDataSets
where dataSet.Location == region
select dataSet;
var queryResult = query.FirstOrDefault();
if (queryResult == null)
{
// do stuff
} else if (queryResult.State != States.Provisioned)
{
// do stuff
}
}
Here is how I am mocking the _utils.GetRegions call, but I dont think thats the problem.
private Mock<IUtils> _mockRegionUtils;
[Fact]
public void ItWorks()
{
// do stuff
_mockRegionUtils = new Mock<IUtils>();
_mockRegionUtils.Setup(utils => utils.GetRegions(It.IsAny<ISomeParam>())).Returns(new List<string>() {"america", "china"});
// call business logic
}
I have checked all the types in the debugger. regionArray.GetType() returns {System.Collections.Generic.List`1[System.String]}. when I type region into the console however, i get:
region
'region' threw an exception of type 'System.NullReferenceException'
how is this possible?
EDIT: fixed a typo above, sorry about that. Something weird though, so if I reassign the value of regionArray to be an inline list, it still fails. But if I define a new inline list and iterate over that, the looping works fine.
List<string> regionArray = new List<string>();
if (someCondition)
{
regionArray = _utils.GetRegions(someParam); // this is not returning null
}
regionArray = new List<string>() {"china", "america"};
List<string> temp = new List<string>() {"foo", "bar"}
foreach (var region in regionArray)
{
// region still throws null reference exception
foreach (var tempVar in temp)
{
var c = tempVar; // this works. tempvar is never null.
}
var query = from dataSet in myDataSets
where dataSet.Location == region
select dataSet;
var queryResult = query.FirstOrDefault();
if (queryResult == null)
{
// do stuff
} else if (queryResult.State != States.Provisioned)
{
// do stuff
}
}
EDIT 2: So I tried iterating over the regionArray in the same way just before the logic above, and it worked fine.
List<string> regionArray = new List<string>();
if (someCondition)
{
regionArray = _utils.GetRegions(someParam); // this is not returning null
}
foreach (var region in regionArray)
{
var c = region; // this works
}
foreach (var region in regionArray)
{
// region throws null reference exception
var query = from dataSet in myDataSets
where dataSet.Location == region
select dataSet;
var queryResult = query.FirstOrDefault();
if (queryResult == null)
{
// do stuff
} else if (queryResult.State != States.Provisioned)
{
// do stuff
}
}
so most likely, it is not a problem with the moq object. based on #Iliar's suggestion, I will see if regionArray gets modified, but at first glance since regionArray is not used within the loop, my answer would be "no".

Update: I got around this issue by renaming the region looping variable to a different name. As it turns out, I was doing another foreach (var region ...) loop earlier in my code. I spoke to some senior colleagues as to why these 2 names would conflict with each other, and they said maybe it was some issue with symbols in VSCode and not really with my actual code. Thank you all for your help!
There was a lot of info in this thread, so just to summarize here are a few bulletpoints in case it is helpful to someone else in the future:
When debugging an XUnit test, I was seeing my looping variable in my foreach displaying the following info in the tooltip 'region' threw an exception of type 'System.NullReferenceException' Data [IDictionary]:{System.Collections.ListDictionaryInternal} HResult [int]:-2147467261 HelpLink [string]:null InnerException [Exception]:null Message [string]:"Object reference not set to an instance of an object." Source [string]:"9dd66c33104045bba27ad3fc9fb95185" StackTrace [string]:" at <>x.<>m0(<IngestEvents>d__13 <>4__this)" TargetSite [MethodBase]:{System.String <>m0(<IngestEvents>d__13)} Static members ....
even as I stepped INTO the loop, the tooltip for region was still showing the above, and when I typed region into the console, I got 'region' threw an exception of type 'System.NullReferenceException'.
The above 2 points led me to believe region was null. However, through #IVSoftware 's help, I verified that region was not actually null, because the assertion was passing.
I then looked at the rest of my code, and as a random guess, I tried renaming the looping variable region to something else. When I did, region was correctly set to the elements of the list.

Hi I really hope to be helpful. First I will answer your question "how is this possible?" and I think I can explain why your edited question with the inline list works. True, the GetRegions method returns a list that is not null. Sure, if you call GetType() on this it correctly identifies it as a "list of strings". I believe however, that the GetRegions method is returning a list that contains at least one null value. And you prove it out yourself when you added the edit, because you say this works:
regionArray = new List<string>() {"china", "america"};
But try making a list with three values like this where one of them is null and probably the loop will fail again.
regionArray = new List<string>() {"china", null, "america"};
This suggests a bug inside the GetRegions method is putting a null value into the list that it is returning. Adding these two lines at the beginning of your loop might go a long way to identifying the issue:
foreach (var region in regionArray)
{
// Look for this in the Visual Studio 'Output' window
System.Diagnostics.Debug.WriteLine(region == null ? "Null" : region);
// You believe that region is not null. So 'assert' that
// this evaluates to True and if it doesn't the debugger will break here.
System.Diagnostics.Debug.Assert(region != null, "Break on this line if region is null");
...
From what I can tell, I would look inside your GetRegions(someParam) method and see if it's inserting a null into the list somewhere. Good luck!

List<string> regionArray = new List<string>();
if (someCondition)
{
regionArray = _utils.GetRegions(someParam); // this is not returning null
}
this will override the regionArray instance, to the GetRegions instance, so creating new List<string> instance is useless.
What you want is :
List<string> regionArray = new List<string>();
if (someCondition)
{
regionArray.AddRange(_utils.GetRegions(someParam));
}
which is using this new instance, and add the resulted elements inside it.
If _utils.GetRegions(someParam) returns empty set, then regionArray will not be null, but it'll be empty regionArray.Count == 0.
this is also can be done using ToList as well:
var regionArray = _utils.GetRegions(someParam).ToList();
now , you need to check regionArray after that :
if(regionArray.Count == 0)
{
// do something
}
Or using Linq
if(!regionArray.Any())
{
// do something
}
if the collection is not empty then you can iterate through the list and validate each string inside this list before you process it:
foreach (var region in regionArray)
{
// check if the element is null or empty
// if true, will skip this element and go to the next one
if(string.IsNullOrEmpty(region)) { continue; } // go to the next iteration
// get the results
var queryResult = myDataSets.FirstOrDefault(x=> x.Location == region);
if (queryResult == null)
{
// do stuff
}
else if (queryResult.State != States.Provisioned)
{
// do stuff
}
}

Related

Roslyn: Check if method parameter can not be null

Using Roslyn, my aim is to check if a method parameter is checked for not being null before the parameter is dereferenced. This check can be in a submethod of course.
My approach is to get the first dereferencing of the parameter and search the syntax tree between that and the method start for null checks. How can I do some kind of control flow analysis to determine if the first dereferencing of the parameter can be reached with the parameter being null?
This is way too broad question, with a little explanation what is your final goal. Are you trying to detect null-pointer exceptions before they even happen, 100%? (Pretty much impossible)
I have written static analysis myself few months ago, I didn't use roslyn, but this doesn't matter.
Check this out to get you possibly started - it's reporting warnings when there are unused variables:
internal class UnUsedVariableWarningDefinition : ICodeIssue
{
public IEnumerable<IssueReport> Analyze()
{
var usageMap = new Dictionary<string, int>(StringComparer.InvariantCultureIgnoreCase);
var variableMap = new Dictionary<string, IdentifierNode>(StringComparer.InvariantCultureIgnoreCase);
foreach (var node in NodeAnalyzerHelper.FindNodesDfs(Root))
{
var assignmentNode = node as AssignmentNode;
if (assignmentNode != null)
{
var variableNode = assignmentNode.Identifier;
int usages;
if (!usageMap.TryGetValue(variableNode.Identifier, out usages))
{
usageMap[variableNode.Identifier] = 0;
variableMap[variableNode.Identifier] = variableNode;
}
}
else
{
// not really an assignmentNode,
// let's see if we have detected the usage of IdentifierNode somewhere.
var variableNode = node as IdentifierNode;
if (variableNode != null)
{
if (usageMap.ContainsKey(variableNode.Identifier))
usageMap[variableNode.Identifier]++;
}
}
}
foreach (var node in usageMap.Where(x => x.Value == 0).Select(x => variableMap[x.Key]))
{
yield return node.ConstructWarning("No usages of this variable found. Are you sure this is needed?");
}
}
}
Notice that FindNodesDfs() is basically a syntax tree walker, which walks syntax nodes depth-first style. What it does is just scans AssigfnmentNodes and puts them to Dictionary, as soon as it identifies IdentifierNode, it checks the dictionary if it has previously encountered assignment, or not. It's a bit similiar what you're trying to do, I guess.

Correct query linq

I already use linq but search id only and it worked perfectly
var obj = (from VAR in db.infos
where VAR.id == 22
select new
{
title = VAR.title,
}).SingleOrDefault();
Label2.Text = obj.title.Trim();
If I try to search by location get a error
var obj = (from VAR in db.infos
where VAR.location.Trim() == "Lim"
select new
{
title = VAR.title.Trim(),
}).SingleOrDefault();
SearchJob.Items.Add(obj.title.Trim());
Label2.Text = obj.title;
Have a error in label2 line
Object reference not set to an instance of an object.
How do I fix it?
if (obj.title != null)
{
SearchJob.Items.Add(obj.title.Trim());
Label2.Text = obj.title;
}
Object reference not set to an instance of an object.
SOLUTION
Change SingleOrDefault() to FirstOrDefault()
You're doing some nasty stuff there, VERY bad habits. For instance this:
var obj = (from VAR in db.infos
where VAR.location.Trim() == "Lim"
select new
{
title = VAR.title.Trim(),
}).SingleOrDefault();
SearchJob.Items.Add(obj.title.Trim());
Label2.Text = obj.title;
Is a nonsense! Let me tell you why:
Always check the data BEFORE you insert it into your database, not AFTER. You're creating a lot of unnecessary overhead this way, which could be avoided altogether. Trim the data before, never after.
Next thing - you need only a single string value, yet you create an anonymous object. WHY? Do this instead:
string title = (from o in db.infos
where o.location == "Lim"
select o.title).SingleOrDefault();
Use SingleOrDefault if you expect a single result or none. However, if you expect multiple results and want only the first, use FirstOrDefault.
As you can see, I'm using o instead of VAR. It's true it doesn't really matter that much, BUT, it's never a good idea to use a word that's very similar to one of the reserved words (var).
If you get an exception Object reference not set to an instance of an object., it means that your query returned a null and you're trying to access a non-existing object. If your query may return null at some point, always check for null when accessing a member!
EDIT
if ( obj.title != null )
is bad too, because you need to check for null the object itself!
if (obj != null)
if you really want to use your bad approach.
I think the error occurred in the query
In first query you have source db.infos
In second you have source db.jobinfos
The source is changed
If we assign empty text to Label it will show, It looks like that obj.title does not exist or you are getting error in your query due to wrong source.
The obj is not returning title field. Check obj by debugging.
Try to skip exception :)
public static class LINQException {
public static void TryExample() {
var LsWithEx = from p in Enumerable.Range(0, 10) select int.Parse("dsfksdj");
var LsSkipEx = (from p in Enumerable.Range(0, 10) select int.Parse("dsfksdj")).SkipExceptions();
}
public static IEnumerable<T> SkipExceptions<T>(this IEnumerable<T> values)
{
using (var enumerator = values.GetEnumerator())
{
bool next = true;
while (next)
{
try
{ next = enumerator.MoveNext();}
catch
{ continue;}
if (next) yield return enumerator.Current;
}
}
}
}
var obj = (from VAR in db.infos
where VAR.location.Trim() == "Lim"
select new
{
title = VAR.title.Trim(),
}).SkipExce.SingleOrDefault();

c# copied property loses reference when referenced object is removed from list

Example
Have a look at the following code:
private void DeDuplicateOrganisations()
{
var profileOrgs = _organisations.Where(o => o.ExistsInProfile).ToList();
var kvkOrgs = _organisations.Where(o => !o.ExistsInProfile).ToList();
profileOrgs.ForEach(o =>
{
var duplicate = kvkOrgs.FirstOrDefault(k => k.KvK == o.KvK || k.Title == o.Title);
if (duplicate != null)
{
o.CompanyInfoOrganisation = duplicate.CompanyInfoOrganisation;
o.ExistsInBoth = true;
kvkOrgs.Remove(duplicate);
}
});
_organisations = profileOrgs.Concat(kvkOrgs).OrderBy(o => o.Title).ToList();
}
In this example the property CompanyInfoOrganisation (simply a get; set; property) is copied when an organisation is considered a duplicate. This all works as expected, duplicates are nicely deduplicated.
Also this is true inside this message:
_organisations.First(o => o.ExistsInBoth).CompanyInfoOrganisation != null;
Problem
Now I bind the _organisations list to a listbox
lbxCompanies.DataSource = null;
lbxCompanies.DataSource = _organisations;
lbxCompanies.DisplayMember = "Title";
lbxCompanies.SelectedIndex = -1;
and later on get the selected value:
var org = lbxCompanies.SelectedValue as Organisation;
gbxCompanyInfo.Visible = org != null;
if (gbxCompanyInfo.Visible)
if (org.CompanyInfoOrganisation != null)
// NEVER GETS HERE (but gbxComanpyInfo is visible)
If I try to read the CompanyInfoOrganisation property I always get null while I know the property was set.
Question
What is happening here? How come the property reference is destroyed? How can I prevent this from happening?
The reference you're using only has immediate scope and as soon as the query ends it exits scope and your reference disappears. So when you bind later, the reference is exactly right -- null.
profileOrgs.ForEach(o =>
{
// Right here -- var duplicate has scope ONLY within your query.
// As soon as the query is executed it leaves scope and the reference
// pointer will be null
var duplicate = kvkOrgs.FirstOrDefault(k => k.KvK == o.KvK || k.Title == o.Title);
if (duplicate != null)
{
o.CompanyInfoOrganisation = duplicate.CompanyInfoOrganisation;
o.ExistsInBoth = true;
kvkOrgs.Remove(duplicate);
}
});
Because you're using a class, you need to perform a deep MemberwiseClone on it to get a NEW copy of the object:
o.CompanyInfoOrganisation = (YourInfoType)duplicate.CompanyInfoOrganisation.MemberwiseClone();
When you load the data, load the CompanyInfoOrganisation property along with the root entity; that way it will be already loaded into memory. If using LINQ to SQL, you load via DataLoadOptions, and pass this to the context. If using Entity Framework, you use the Include method in the LINQ query.
It might have to do with capturing of variables inside the lambda. Try substituting the .ForEach to a regular foreach().
Or maybe the CompanyInfoOrganisation in duplicate was null to begin with.
The problem was I used string.Join() to show the values, and the first value to join was null (which is really annoying), resulting in an empty string, leaving me thinking the property was null. However it turned out the property was not null, but has a perfectly valid reference to the object needed. Using the debugger with a little more care would have saved me an hour or so...
Sorry!

Not all code paths return a value

I am having this Linq To SQL query which is taking Customer Category from database.The CustCategory will be defined already.Here is the query.
public IList<string> GetAccountType()
{
using (var db = new DataClasses1DataContext())
{
var acctype = db.mem_types.Select(account=>account.CustCategory).Distinct().ToList();
if (acctype != null)
{
return acctype;
}
}
}
Currently I am getting an error that Not all code paths return a value.If I am always certain that the value is there in the database then do I need to check for null,If I need to check for null then how do I handle this.
Can anyone help me with this.
Any suggestions are welcome.
Since Enumerable.ToList never returns null (see the Return Value section of the documentation), you can safely remove the if.
EDIT: Note that, no matter what your database contains, acctype will never be null:
If no value is found in the database, the return value will be an empty list (which is different than null).
If one record is found and its value is null, the return value will be a valid list with one entry, whose value is null. Still, the list itself is not null.
What happens if:
if (acctype != null)
Is null? What is your method supposed to return?
You need to return something
This is not about LINQ to SQL, the method GetAccountType() must return IList<string>. You should return return acctype; and then check this returned list later using Any(), something like:
if(GetAccountType.Any()){
//not empty
}
How about something like this for a fairly clean and readable solution?:
(Note, updated: removed the check for null, since it would clearly not have any effect).
public IList<string> GetAccountType()
{
var acctype = new List<string>();
using (var db = new DataClasses1DataContext())
{
acctype = db.mem_types.Select(
account=>account.CustCategory).Distinct().ToList();
}
return acctype;
}
You need to return a value from your function:
public IList<string> GetAccountType()
{
using (var db = new DataClasses1DataContext())
{
var acctype = db.mem_types.Select(account=>account.CustCategory).Distinct().ToList();
if (acctype != null)
{
return acctype;
}
}
return acctype;
}

Null Object Reference

Using Nunit to test C# code with the following code block:
foreach (XmlNode node in nodeList)
{
thisReport.Id = node.Attributes.GetNamedItem("id").Value;
thisReport.Name = node.Attributes.GetNamedItem("name").Value;
thisReport.Desc = node.Attributes.GetNamedItem("desc").Value;
if (node.SelectNodes("subreport").Count > 0)
{
thisReport.HasSubReport = true;
subReportNodeList = node.SelectNodes("subreport");
foreach(XmlNode subNode in subReportNodeList)
{
mySubReport.ParentID = node.Attributes.GetNamedItem("id").Value;
mySubReport.Priority = subNode.Attributes.GetNamedItem("priority").Value;
mySubReport.SubReportId = subNode.Attributes.GetNamedItem("id").Value;
mySubReport.SubReportName = subNode.Attributes.GetNamedItem("name").Value;
string sTime = subNode.Attributes.GetNamedItem("time").Value;
mySubReport.Time = Convert.ToInt16(sTime);
thisReport.SubReportsList.Add(mySubReport);
}
}
else
{
thisReport.HasSubReport = false;
}
reports.Add(thisReport);
}
The code fails with a null object reference on the line:
thisReport.SubreportsList.Add(mySubReport)
But looking at the locals, thisReport exists and has the values assigned at the top of the block, and mySubReport exists and has the values assigned just above the line where it's added to thisReport. All the values in mySubReport are valid and SubReportsList in thisReport is a generic list of type SubReport.
So, where's the null? It seems so simple, it must be something really obvious that I can't see.
You've not instantiated SubReportsList before calling Add. Do the following before adding mySubReport:
thisReport.SubReportsList = new List<SubReport>();
thisReport.SubReportsList.Add(mySubReport);
You could also change your SubReportsList property to make your life easier:
public class Report
{
public IList<SubReport> SubReportsList
{
get
{
if (_subReportsList == null)
{
_subReportsList = new List<SubReport>();
}
return _subReportsList;
}
}
private IList<SubReport> _subReportsList;
}
Doing this would instantiate your List if it's called while it's null.
You should probably first do:
thisReport.SubReportsList = new List<SubReport>();
It must be SubReportsList that is null then.
As #GenericTypeTea and #Dan Dumitru have already provided good answers I will just add that it is possible to "automatically" do this by adding an implicit construction if the value is null when you call the property. You can do this if you are not using auto-properties ala:
public class Report {
// ... other code ...
private List<SubReports> _subReports = null;
public List<SubReport> SubReports {
get {
if (_subReports == null) { _subReports = new List<SubReports>(); }
return _subReports;
}
}
}
There are some caveats to be noted, like making it thread-safe (this is off-the-cuff), but the basic implementation will work for you. I would be careful using this desing as it can cause the creation of objects you don't necessarily need just by checking properties. If that is undesirable then stick with the implementations recommended above.
thisReport.SubReportsList is your null reference; you've declared it but not initialized it. You can initialize it (probably with a new instance) either in a constructor for thisReport's type, or just before you start adding things to it.
Make sure to initialize the list by using the new keyword. Otherwise the list itself will be null.

Categories

Resources