System.NullReferenceException based on List<int> [duplicate] - c#

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 7 years ago.
I'm trying to loop through rows and get their Indexes (Primary Keys from SQL). I'm getting a NRE on "this.SelectRowIndexes.Add(ResourceKey)" I can't figure out why it would matter and how can I fix this?
CODE:
private void GetIndexes()
{
List<int> SelectRowIndexes = new List<int>();
for (int i = 0; i < gridViewRecords.Rows.Count; i++)
{
DataRowView drv = (DataRowView)gridViewRecords.CurrentRow.DataBoundItem;
DataRow selectedRow = drv.Row;
ResourceKey = Convert.ToInt32(selectedRow["ResourceAndInstallKey"]);
this.SelectRowIndexes.Add(ResourceKey);
}
}
I also have it up in my class (this has been a ton of troubleshooting, so my code looks terrible)
public List<int> SelectRowIndexes { get; set; }
I had this prior. Several of the answers quoted this code. I changed mine because the if-else was actually used for something else, which has now been deleted
if (this.SelectRowIndexes == null)
{
this.SelectRowIndexes.Add(ResourceKey);
}
else
{
this.SelectRowIndexes.Add(ResourceKey);
}

If SelectRowIndexes is null then you can't add anything to the list. You first need to initialize an empty list with
this.SelectRowIndexes = new List<int>();

What do you actually want to do if this.SelectRowIndexes is null? Currently you're just unconditionally calling Add on it, because both branches of your if statement do the same thing.
Note that it definitely wouldn't be null if you'd assigned a new value to it - but instead in this line, you're declaring a new local variable called SelectRowIndexes:
List<int> SelectRowIndexes = new List<int>();
... which you're then completely ignoring. Perhaps you meant to set the value of the property/field instead?
SelectRowIndexes = new List<int>();
With that change, you should avoid the exception - but you'll still have the basically-broken code. You should almost certainly just get rid of the if check... it's not doing you any good right now.
However, I would suggest that you probably should be declaring a separate local variable for resourceKey - the fact that you're updating an instance variable in a loop is somewhat peculiar... as is the fact that you're not using your loop index at all... you're doing the same thing for each iteration of the loop, using the current row rather than row i. Is that deliberate?
Fundamentally, you might well want to start this code again... it looks like you might just want to use LINQ:
private void GetIndexes()
{
SelectRowIndexes = gridViewRecords.Rows
.Cast<DataRowView>()
.Select(drv => (int) drv.Row["ResourceAndInstallKey"])
.ToList();
}

The this keyword allows you to access a member named SelectRowIndexes within the scope of the class. That member is probably not initialized. Remove the List<int> type declaration and it will be perfect.
private List<int> SelectRowIndexes;
private void GetIndexes()
{
SelectRowIndexes = new List<int>();
for (int i = 0; i < gridViewRecords.Rows.Count; i++)
{
DataRowView drv = (DataRowView)gridViewRecords.CurrentRow.DataBoundItem;
DataRow selectedRow = drv.Row;
ResourceKey = Convert.ToInt32(selectedRow["ResourceAndInstallKey"]);
if (this.SelectRowIndexes == null)
{
this.SelectRowIndexes.Add(ResourceKey);
}
else
{
this.SelectRowIndexes.Add(ResourceKey);
}
}
}

You instantiate a local variable
List<int> SelectRowIndexes = new List<int>();
and then you are adding to your class property/field this.SelectedRowIndexes which you are most likely not assigning anywhere and it is null and you get NRE.
this.SelectRowIndexes.Add(ResourceKey);
Change this so
private void GetIndexes()
{
this.SelectRowIndexes = new List<int>();
for (int i = 0; i < gridViewRecords.Rows.Count; i++)
{
DataRowView drv = (DataRowView)gridViewRecords.CurrentRow.DataBoundItem;
DataRow selectedRow = drv.Row;
ResourceKey = Convert.ToInt32(selectedRow["ResourceAndInstallKey"]);
this.SelectRowIndexes.Add(ResourceKey);
}
}

Related

C# how can I loop through all Elements of a List <string>

I have the following problem. I have a list of strings and want to split these. After that, I want to give each Object Element a reference to an item of the List.
Example:
List<string> valueList = attr.Split(' ').ToList<string>();
This List has items like that:
name,string,age,int
For this example every Object needs to get 2 pieces of information, first the name (out of example: "name" or "age") and second the type (out of example: "string", "int").
Now I want to get an Object with this informations. So I created Objects and put these Objects into a List.
Example:
List<MyObject> listObjects = new List<MyObject>();
for (int i = 0; i < ValueList.Count; i++)
{
MyObject object = new MyObject();
if (ValueList.Any(s => s.StartsWith(modifier)) == true)
{
object.name = ValueList[i];
object.type = ValueList[i + 1];
}
listObjects.Add(object);
}
But with my solution, I'm getting a System.ArgumentOutOfRangeException. My explanation for this would be the foreach but I don't know a technique on how to get every item of the List of strings and add these to objects. Also what a problem is that 1 item of the List should have 2 elements (name, type) but with my method, I'm going through the foreach for every element. Is there any better way to do it in C# .Net Framework?
I suppose that you want something like this.
// Store your relevant keywords in a list of strings
List<string> datatypes = new List<string>{"string", "int"};
// Now loop over the ValueList using a normal for loop
// starting from the second elemend and skipping the next
for(int x = 1; x < ValueList.Count; x+=2)
{
// Get the current element in the ValueList
string current = ValueList[x];
// Verify if it is present in the identifiers list
if (datatypes.Contains(current)))
{
// Yes, then add the element before the current and the current to the MyObject list
MyObject obj = new MyObject;
obj.name = ValueList[x - 1];
obj.type = current;
listObjects.Add(obj);
}
}

c# list in property which is array

This is my property class:
class Actions
{
public string[] Style { get; set; }
}
and this is my main method:
Actions action = new Actions();
List<string> list = new List<string>();
list.Add("one");
list.Add("two");
foreach (var item in list)
{
for (int i = 0; i < action.Style.Length; i++)
{
action.Style[i] = item.ToString();
Console.WriteLine(action.Style[i]);
}
}
How do I fill the property with list items?
This gives me a exception:
"object reference not set to an instance of an object".
There is no need to add your items one by one, you could just use the ToArray() method of your list like so:
List<string> list = new List<string>();
list.Add("one");
list.Add("two");
Actions action = new Actions {
Style = list.ToArray()
};
As has already been pointed out, Style is always null, given the code you have shared. #Eldeniz and #paul have shared different ways to fix that. Obviously, your sample code is just a sample fragment, so here are 2 other options you could consider if the previous two don't work for whatever reason (I'm just free-handing this, please excuse any typos).
1) You can have your Actions class always return a not-null object
class Actions
{
private string[] _style;
public string[] Style
{
get { return _style ?? new string[0]; }
set { _style = value; }
}
}
Note that this will allow you to always see the output of the style property as requested, assuming an empty array and null are, for your purposes, the same thing.
2) You can make your loop tolerant to null values
foreach (var item in list)
{
for (int i = 0; i < action?.Style.Length ?? 0; i++)
{
action.Style[i] = item.ToString();
Console.WriteLine(action.Style[i]);
}
}
Finally, just as a tip, if you have your debugger attached and you are stepping through your code, Visual Studio will help you pinpoint these sorts of errors pretty easily. Take the time to become friends with your debugger. If it gives you an error you don't understand, do a quick web search. Your future self will thank you.
You must create an instance of the Style property
List<string> list = new List<string>();
list.Add("one");
list.Add("two");
Actions action = new Actions();
action.Style=new string[list.Count];
foreach (var item in list)
{
for (int i = 0; i < action.Style.Length; i++)
{
action.Style[i] = item.ToString();
Console.WriteLine(action.Style[i]);
}
}

How do I delete a datarow from a datarow array?

I am looping through a array of datarows and when a particular random item is not valid I want to remove that item and get the new total to get another random item.
But when I delete a datarow the datarow does not go away... And yes there is probably a much better way to do this but I am not smart enough to do it..
Instead of removing the row I see this inside
ItemArray = podLps[1].ItemArray threw an exception of type System.Data.RowNotInTableException
//PHASE 1: Get all LPs in the pod and add to collection
List<DataRow> allLps = dtLp.AsEnumerable().ToList();
DataRow[] podLps = allLps.Where(x => x.ItemArray[0].ToString() == loPod).ToArray();
//PHASE 2: Pick a random LP from collection that has valid WAVE1
for (int i = podLps.Count(); i > 0; i--)
{
//Recount items in collection since one may have been removed
int randomIndex = random.Next(podLps.Count());
var randomLpUserId = podLps[randomIndex].ItemArray[1].ToString();
var randomLpWave1 = int.Parse(podLps[randomIndex].ItemArray[2].ToString());
//Get WAVE1 # for selected LP
lpNumberOfLoans = GetNumberOfLoans(session, randomLpUserId);
//check if LP has valid WAVE1 then use this person
if (randomLpWave1 > lpNumberOfLoans)
{
return randomLpUserId;
}
else
{
podLps[randomIndex].Delete();
}
}
look at this example and it should point you in the right direction for removing rows I just tested it and it works
for (int i = myDataTable.Rows.Count - 1; i >= 0; i--)
{
DataRow row = myDataTable.Rows[i]; //Remove
if (myDataTable.Rows[i][0].ToString() == string.Empty)
{
myDataTable.Rows.Remove(row);
}
}
I would suggest to use a List for podLps instead of an array.
Then you can use .RemoveAt as Jaco mentioned (dosn't work for arrays).
DataRow.Delete() just flags the Row to be deleted in the next update of your DataTable.
The easiest method is to convert your array of DataRow[] to a List, call RemoveAt and then convert the list back to an array:
var dest = new List<>(podLps);
dest.RemoveAt(randomIndex);
podLps = dest.ToArray();

Creating an array from scratch while code is running

I am trying to create a list via array like this:
private Application[] GetApps()
{
DataSet ds = new Dataset();
string query = "query";
ds = GetData(query);
var appList = new Application[ds.Tables[0].Rows.Count];
for(var i = 0; i <= ds.Tables[0].Rows.Count - 1; i++)
{
DataRow item = ds.Tables[0].Rows[i];
appList[i].Name = item["Name"].ToString();
appList[i].Confidentiality = int.Parse(item["Conf"].ToString());
appList[i].Id = item["ID"].ToString();
}
return appList;
}
I keep getting an object null error and I know I have to be missing something completely obvious that I'm just not seeing. Do I need to declare the new array in some other way?
When you create appList, you are only creating the array itself. .NET does not automatically populate the array with Application objects for you to manipulate. You need to create a new Application object, and set the properties on that object, then you can assign the object to the array.
There are multiple Application classes withing the .NET framework, none of which seem to match your code, so the below example will simply assume that Application is a custom type of your own design.
for(var i = 0; i < ds.Tables[0].Rows.Count; i++)
{
DataRow item = ds.Tables[0].Rows[i];
Appliction app = new Application();
app.Name = item["Name"].ToString();
app.Confidentiality = int.Parse(item["Conf"].ToString());
app.Id = item["ID"].ToString();
appList[i] = app
}
As an aside, note that you can replace i <= x - 1 with i < x and the behavior is exactly the same.
Finally, you should introduce checks for all of your accessors if there is a chance that they could return null. For example, if item["Name"] returns null, then calling item["Name"].ToString() is equivelant to calling null.ToString(), which will also result in a NullReferenceException.

how to dissect string values

How can I dissect or retrieve string values?
Here's the sample code that I'm working on now:
private void SplitStrings()
{
List<string> listvalues = new List<string>();
listvalues = (List<string>)Session["mylist"];
string[] strvalues = listvalues.ToArray();
for (int x = 0; x < strvalues.Length; x++)
{
}
}
Now that I'am able to retrieve list values in my session. How can I separately get the values of each list using foreach or for statement?
What I want to happen is to programmatically split the values of the strings depending on how many is in the list.
If you have a list of string values, you can do the following:
private void SplitStrings()
{
List<string> listValues = (List<string>) Session["mylist"];
// always check session values for null
if(listValues != null)
{
// go through each list item
foreach(string stringElement in listValues)
{
// do something with variable 'stringElement'
System.Console.WriteLine(stringElement);
}
}
}
Note that I test the result of casting the session and that I don't create a new list first-off, which is not necessary. Also note that I don't convert to an array, simply because looping a list is actually easier, or just as easy, as looping an array.
Note that you named your method SplitStrings, but we're not splitting anything. Did you mean to split something like "one;two;three;four" in a four-element list, based on the separator character?
I'm not sure what you're trying to obtain in this code, I don't know why you're converting your List to an Array.
You can loop through your listValues collection with a foreach block:
foreach(string value in listValues)
{
//do something with value, I.e.
Response.Write(value);
}
I don't know what's in the strings but you can start by simplifying. There is no point allocating a new List if you're going to overwrite it immediately.
private void SplitStrings()
{
List<string> list = (List<string>)Session["mylist"];
foreach(string value in list)
{
}
}
List listvalues = (List)Session["mylist"];
foreach (string s in listvalues)
{
//do what you want with s here
}

Categories

Resources