c# modifying structs in a List<T> - c#

Short question: How can I modify individual items in a List? (or more precisely, members of a struct stored in a List?)
Full explanation:
First, the struct definitions used below:
public struct itemInfo
{
...(Strings, Chars, boring)...
public String nameStr;
...(you get the idea, nothing fancy)...
public String subNum; //BTW this is the element I'm trying to sort on
}
public struct slotInfo
{
public Char catID;
public String sortName;
public Bitmap mainIcon;
public IList<itemInfo> subItems;
}
public struct catInfo
{
public Char catID;
public String catDesc;
public IList<slotInfo> items;
public int numItems;
}
catInfo[] gAllCats = new catInfo[31];
gAllCats is populated on load, and so on down the line as the program runs.
The issue arises when I want to sort the itemInfo objects in the subItems array.
I'm using LINQ to do this (because there doesn't seem to be any other reasonable way to sort lists of a non-builtin type).
So here's what I have:
foreach (slotInfo sInf in gAllCats[c].items)
{
var sortedSubItems =
from itemInfo iInf in sInf.subItems
orderby iInf.subNum ascending
select iInf;
IList<itemInfo> sortedSubTemp = new List<itemInfo();
foreach (itemInfo iInf in sortedSubItems)
{
sortedSubTemp.Add(iInf);
}
sInf.subItems.Clear();
sInf.subItems = sortedSubTemp; // ERROR: see below
}
The error is, "Cannot modify members of 'sInf' because it is a 'foreach iteration variable'".
a, this restriction makes no sense; isn't that a primary use of the foreach construct?
b, (also out of spite) what does Clear() do if not modify the list? (BTW, the List does get cleared, according to the debugger, if I remove the last line and run it.)
So I tried to take a different approach, and see if it worked using a regular for loop. (Apparently, this is only allowable because gAllCats[c].items is actually an IList; I don't think it will allow you to index a regular List this way.)
for (int s = 0; s < gAllCats[c].items.Count; s++)
{
var sortedSubItems =
from itemInfo iInf in gAllCats[c].items[s].subItems
orderby iInf.subNum ascending
select iInf;
IList<itemInfo> sortedSubTemp = new List<itemInfo>();
foreach (itemInfo iInf in sortedSubItems)
{
sortedSubTemp.Add(iInf);
}
//NOTE: the following two lines were incorrect in the original post
gAllCats[c].items[s].subItems.Clear();
gAllCats[c].items[s].subItems = sortedSubTemp; // ERROR: see below
}
This time, the error is, "Cannot modify the return value of 'System.Collections.Generic.IList.this[int]' because it is not a variable." Ugh! What is it, if not a variable? and when did it become a 'return value'?
I know there has to be a 'correct' way to do this; I'm coming to this from a C background and I know I could do it in C (albeit with a good bit of manual memory management.)
I searched around, and it seems that ArrayList has gone out of fashion in favor of generic types (I'm using 3.0) and I can't use an array since the size needs to be dynamic.

Looking at the for-loop approach, the reason (and solution) for this is given in the documentation for the compilation error:
An attempt was made to modify a value
type that is produced as the result of
an intermediate expression but is not
stored in a variable. This error can
occur when you attempt to directly
modify a struct in a generic
collection.
To modify the struct, first assign it
to a local variable, modify the
variable, then assign the variable
back to the item in the collection.
So, in your for-loop, change the following lines:
catSlots[s].subItems.Clear();
catSlots[s].subItems = sortedSubTemp; // ERROR: see below
...into:
slotInfo tempSlot = gAllCats[0].items[s];
tempSlot.subItems = sortedSubTemp;
gAllCats[0].items[s] = tempSlot;
I removed the call to the Clear method, since I don't think it adds anything.

The problem you are having in your foreach is that structs are value types, and as a result, the loop iteration variable isn't actually a reference to the struct in the list, but rather a copy of the struct.
My guess would be the compiler is forbidding you change it because it most likely would not do what you expect it to anyway.
subItems.Clear() is less of a problem, because altho the field may be a copy of the element in the list, it is also a reference to the list (shallow copy).
The simplest solution would probably be to change from a struct to a class for this. Or use a completely different approach with a for (int ix = 0; ix < ...; ix++), etc.

The foreach loop doesn't work because sInf is a copy of the struct inside items. Changing sInf will not change the "actual" struct in the list.
Clear works because you aren't changing sInf, you are changing the list inside sInf, and Ilist<T> will always be a reference type.
The same thing happens when you use the indexing operator on IList<T> - it returns a copy instead of the actual struct. If the compiler did allow catSlots[s].subItems = sortedSubTemp;, you'll be modifying the subItems of the copy, not the actual struct. Now you see why the compiler says the return value is not a variable - the copy cannot be referenced again.
There is a rather simple fix - operate on the copy, and then overwrite the original struct with your copy.
for (int s = 0; s < gAllCats[c].items.Count; s++)
{
var sortedSubItems =
from itemInfo iInf in gAllCats[c].items[s].subItems
orderby iInf.subNum ascending
select iInf;
IList<itemInfo> sortedSubTemp = new List<itemInfo>();
foreach (itemInfo iInf in sortedSubItems)
{
sortedSubTemp.Add(iInf);
}
var temp = catSlots[s];
temp.subItems = sortedSubTemp;
catSlots[s] = temp;
}
Yes, this results in two copy operations, but that's the price you pay for value semantics.

The two errors you specified have to do with the fact that you are using structs, which in C# are value types, not reference types.
You absolutely can use reference types in foreach loops. If you change your structs to classes, you can simply do this:
foreach(var item in gAllCats[c].items)
{
item.subItems = item.subItems.OrderBy(x => x.subNum).ToList();
}
With structs this would need to change to:
for(int i=0; i< gAllCats[c].items.Count; i++)
{
var newitem = gAllCats[c].items[i];
newitem.subItems = newitem.subItems.OrderBy(x => x.subNum).ToList();
gAllCats[c].items[i] = newitem;
}
The other answers have better information on why structs work different than classes, but I thought I could help with the sorting part.

If subItems was changed to a concrete List instead of the interface IList, then you'd be able to use the Sort method.
public List<itemInfo> subItems;
So your whole loop becomes:
foreach (slotInfo sInf in gAllCats[c].items)
sInf.subItems.Sort();
This won't require the contents of the struct to be modified at all (generally a good thing). The struct's members will still point to exactly the same objects.
Also, there are very few good reasons to use struct in C#. The GC is very, very good, and you'd be better off with class until you've demonstrated a memory allocation bottleneck in a profiler.
Even more succinctly, if items in gAllCats[c].items is also a List, you can write:
gAllCats[c].items.ForEach(i => i.subItems.Sort());
Edit: you give up too easily! :)
Sort is very easy to customise. For example:
var simpsons = new[]
{
new {Name = "Homer", Age = 37},
new {Name = "Bart", Age = 10},
new {Name = "Marge", Age = 36},
new {Name = "Grandpa", Age = int.MaxValue},
new {Name = "Lisa", Age = 8}
}
.ToList();
simpsons.Sort((a, b) => a.Age - b.Age);
That sorts from youngest to oldest. (Isn't the type inference good in C# 3?)

Related

Why is this Linq not working

I have a rather ugly object (yeah, I need the Tuple there :) ):
var roomToIndex = new Dictionary<RoomNode, Tuple<Int32, Dictionary<GrowDirections, Int32>>>();
I initialize this Dictionary like this:
for (var i = 0; i < roomsAdjacent.Count(); i++) {
roomToIndex.Add(roomsAdjacent.ElementAt(i), new Tuple<Int32, Dictionary<GrowDirections, Int32>>(i, new Dictionary<GrowDirections, Int32>()));
roomToIndex.ElementAt(i).Value.Item2.Add(GrowDirections.Top, 0);
roomToIndex.ElementAt(i).Value.Item2.Add(GrowDirections.Right, 0);
roomToIndex.ElementAt(i).Value.Item2.Add(GrowDirections.Bottom, 0);
roomToIndex.ElementAt(i).Value.Item2.Add(GrowDirections.Left, 0);
}
Where roomsAdjacent is a List of RoomNodes and GrowDirections a [Flags] Enumerable.
After those initialization steps I increment the Integer values of the 'inner' Dictionaries and at last I want to get the GrowDirection and RoomNode with the biggest value.
I try to do that the following way (now):
///Use the Counts to determine optimal FillDirection
var rDC = roomToIndex
///Select the RoomNode and the GrowDirection (incl. Count) with the highest Count for each Room
.Select(r => new { RoomNode = r.Key, Dict = r.Value.Item2.OrderByDescending(dirCount => dirCount.Value).ToList()[0] })
///Order those RoomNodes and GrowDirections descending
///Take the first Element and used the Dict's Key (GrowthDirection)
.OrderByDescending(rGI => rGI.Dict.Value).ToList();
var rDC0 = rDC[0];
if (rDC0.Dict.Key == GrowDirections.Top || rDC0.Dict.Key == GrowDirections.Bottom)
fillDirection = GrowDirections.Top | GrowDirections.Bottom;
else
fillDirection = GrowDirections.Right | GrowDirections.Left;
foreach (var rTI in roomToIndex.Where(rTI => rTI.Key != rDC0.RoomNode))
roomCellCount[rTI.Value.Item1] = 0;
The rDC has a Type of { RoomNode, Dictionary } and I have no Problem there.
But when I debug and step to the next line:
var rDC0 = rDC[0];
The debugger skips the line, goes right to the 'if statement' and throws an error, telling me that I got a NullReferenceException??!!
When I look at the values in my 'rDC object' there is no null-Value.
What can it be? Thank you for any tip/help :)
Examining your code the type of rDC is List<KeyValuePair<RoomNode, something very complicated>. The important thing is not something very complicated but that KeyValuePair<TKey, TValue> is a value type (struct). This means that List<KeyValuePair<TKey, TValue>> cannot have elements that are null. This means that rDC0 cannot be null. This is basically also what you tell us.
But then, if you get a NullReferenceException as you describe, it must be rDC0.Dict that is null. However, the Dict property cannot be null because it has very clearly been initialized to a new Dictionary<GrowDirections, Int32> by your initialization code.
So the code you have provided in the question should not be able to exhibit the behavior your describe. Either your code is somewhat different or the behavior you get is not exactly as you describe. The debugger problem you mention could be either a result of debugging the release version or symbols being out of sync with the executable code.
I suggest that you try one or more of the following things to fix your problem:
Rebuild the solution to make sure the debugger shows the correct source code when you debug
Switch to a debug build to turn off optimizations that will make debugging confusing
Break your data and code into smaller parts to get rid of the complicated and hard to understand code you have
The last suggestion is what will solve (or has solved) your problem. Let me just give you a few pointers:
Instead of using Dictionary<GrowDiretions, Int32> you could perhaps create a type with four properties which hopefully would make it more clear what your code is doing:
class GrowCounts {
public Int32 TopCount { get; set; }
public Int32 RightCount { get; set; }
public Int32 BottomCount { get; set; }
public Int32 LeftCount { get; set; }
public GrowDirections MaxGrowDirection {
get { // Return GrowDirections.Top if TopCount has the highest count etc. }
}
}
Instead of using new Tuple<T1, T2> use Tuple.Create to let the compiler infer the types of the tuple.
Do you really need the Tuple where the first element is an index? Some of your code uses for loops with Count and ElementAt and accessing collections in that way requires an index. However, maybe you could convert these loops into foreach loops and in the process you would discover that the index is unneeded. If that was possible you could get rid of the Tuple.
Apparently (according to what you wrote) it has to do with the the complex Linq statement, which had a side-effect that is somehow leading to the null reference error, which putting it in its own function contained. You might be able to get more clues about what exactly caused that, by seeing what happens if you put a simpler Linq Select statement before the initialization. See Martin's more comprehensive later suggestion about how you could track down what's actually going on here.

Get data from arraylist of Structs, then inserting more data into other elements of the struct

I have an Arraylist of Structs called tag (shown below) and I can successfully import data into the structure. (The data shows up correctly when I debug.)
How can I access the data and write it to other elements in the structure?
struct tag
{
public string name;
public string type;
public string rack;
public string card;
public string channel;
public string data;
public string fault;
};
ArrayList TagList = new ArrayList();
importTag.name = "aName";
importTag.type = "atype";
importTag.rack = "arack";
importTag.card = "acard";
importTag.channel "achannel";
TagList.Add(importTag);
foreach (tag t in TagList){
//tasty stuff in here
//
}
You shouldn't use a struct here in the first place. To being with, mutable structs are evil. When you have a mutable struct you end up mutating a copy of the value instead of the value itself, so the code looks sensible, but doesn't actually work. This is why structs should virtually always be immutable.
Next, your struct doesn't represent a single value; if you're making a struct, it should represent a singular logical value.
You also shouldn't use a struct if it's large; your struct is quite large. This means all of that data is constantly being copied around.
You also shouldn't use a struct when it'll be boxed often, and you're boxing the structs that you're using.
You should use a class instead. If you change your code to use a class rather than a struct, and also use a List instead of an ArrayList to leverage generics, then after that your code can become:
foreach(tag t in tagList)
{
t.name = "new name";
}
If you insist on using a struct despite the fact that it violates all of the guidelines for when to use a struct then you'll need to create a new struct based on the new and old values and assign that new struct to the list:
for(int i = 0; i < tagList.Count; i++)
{
tagList[i] = new tag
{
name = "new name",
type = tagList[i].type,
rack = tagList[i].rack,
card = tagList[i].card,
channel = tagList[i].channel,
data = tagList[i].data,
fault = tagList[i].fault,
};
}
If you are creating collection of same data then use strictly typed collections like List
List<tag> tagList = new List<tag>();
And because you are using ArrayList it returns each 'tag' as object so you need to do casting but if you are using above approach you can access list elements like this :
foreach(tag t in tagList)
{
t.name = "your data";
}
Hope this helps.
Avoid using ArrayList with structs. If you use List<tag> rather than ArrayList, then you can modify items in the struct using:
List<tag> myList;
for (int i=0; i < myList.Count; i++)
{
var temp = myList[i];
temp.card = "New value";
myList[i] = temp;
}
If you don't mind using an array and managing the size yourself, then you can do something like:
tag[] myTags = new tag[16];
int myTagsCount;
void AddTag(tag newTag)
{
if (myTagsCount >= myTags.Length)
Array.Resize(ref myTags, myTagsCount*2);
myTags[myTagsCount++] = newTag;
}
... and then when you want to modify each tag:
for (int i=0; i < myTags.Length; i++)
{
myTags[i].card = "New Value"; // Arrays allow efficient in-place modification of structures
}
Note that if you use mutable class instead of a structure, some operations will be more convenient but you need to make sure that you never store into any collection which is supposed to hold tag values any reference to a tag which might be modified elsewhere. Immutable classes will make sharing data a little easier and more efficient, but the only way to change what's encapsulated within a field or collection member will be to replace it with an entirely new object instance. Structures often represent a very useful compromise.
I'm not sure if I understood you correctly but, do you what to do this?
foreach (tag t in TagList){
t.name = "My New Name";
}

Update the property of a struct within a List in C#

I have a List<Cat> where Cat is a struct that has an Id and a Name.
How do I change the name of the cat with id 7?
I did (without thinking)
var myCat = catList.Single(c => c.Id == 7);
mycat.Name = "Dr Fluffykins";
But of course, structs are value types. So is it possible to use a technique like this, or do I have to change .Single into a for loop and store the index to replace it with the updated struct?
Since structs are value types, and because value types get copied, myCat ends up with the copy of the cat from the list. You need to operate on the struct itself, not its copy.
Moreover, you can modify fields of structs directly only when they are single variables or parts of an array. List<T>'s indexer returns a copy, so C# compiler produces the "Cannot modify a value type" error.
The only solution that I know (short of making Cat a class or re-assigning a modified copy) is making catList an array:
var indexOf = catArray
.Select((Cat, Index) => new {Cat, Index})
.Single(p => p.Cat.Id == 7).Index;
catArray[indexOf].Name = "Dr Fluffykins";
To update the value of the item in the list whose ID is seven, one must first find its location within the list. Once its index is known, one can update it using the normal approach which is applicable to all exposed-field structures:
int index = myList.Find( it => it.ID == 7);
if (index >= 0)
{
var temp = myList[index];
temp.Name = "Dr Fluffykins";
myList[index] = temp;
}
Note that some people think structs are inferior to classes because the above code will never work without the last line. I would argue the opposite: in many cases, they're superior because merely knowing that something is an exposed-field struct is sufficient to know that the last line will be necessary and sufficient. By contrast, if the type in question were a mutable class, the code, with or without the last line, might work as expected or might have unintended side-effects.
Incidentally, if one will be using Id a lot, I would suggest using a Dictionary<int, Cat> rather than a List<Cat>. Alternatively, you could use a Cat[] along with a Dictionary<int,int> to keep track of the locations of different cats within the array. One advantage of this latter approach is that with a Cat[], unlike a List<Cat>, one can simply say:
myArray[index].Name = "Dr Fluffykins";
to update the item in the array directly. Such an approach is very performant. Alternatively, you could write a List<T>-like class which includes a methods "ActOnItem(int index, ref T it) and ActOnItem<TParam1>(int index, ref T it, ref TParam1 param1) method, which could be invoked myList.ActOnItem(index, (ref Cat it)=>it.Name = "Dr Fluffykins"); or--if theNewName is a variable, myList.ActOnItem(index, (ref Cat it, ref string TheNewName)=>it.Name = theNewName); Note that one could store theNewName to the item without passing it as a ref or non-ref parameter, but lambdas which close local variables are much slower than those which don't.

Getting a ref/address from a list in C#

I am aware that C# does not deal with pointers but I wonder if I can get a ref to a list when I know its first element?
For example:
Let's say I have a list defined as
List<T> abc
If I have abc[0], can I get a reference of abc?
I am new to C#, I apologize if my question seems weird. In C/C++, I can get the address of an array abc by using &abc[0]. Does C# provide us with similar tool that help us refer back to the collection itself when we know one item in the collection?
Thanks,
This is now possible, starting with .NET 5.0, by using the System.Runtime.InteropServices.CollectionsMarshal.AsSpan method.
As indicated by the documentation, items should not be added to or removed from the list while using the span or item references taken from the span. Technically this should also be extended to say that the Capacity should not be changed nor should TrimExcess() be called. If these operations are used while actively using the span or its references, then the internal memory of the list may no longer be the same as the memory in the span.
// Create a simple list with three items.
var list = new List<int>();
list.Add(123);
list.Add(456);
list.Add(789);
// Print list to console.
Console.WriteLine("List items:");
foreach (var item in list)
Console.WriteLine(item);
Console.WriteLine();
// Get a reference to the second item in the list.
// WARNING: DO NOT ADD/REMOVE ITEMS FROM THE LIST WHILE USING THIS SPAN
// OR ANY REFERENCES DERIVED FROM THIS SPAN!
var listSpan = CollectionsMarshal.AsSpan(list);
ref var secondItem = ref listSpan[1];
Console.WriteLine($"Referenced value (original): {secondItem}");
// Change the referenced list item.
secondItem = 0;
Console.WriteLine($"Referenced value (modified): {secondItem}");
Console.WriteLine();
// Print the list to console.
Console.WriteLine("List items:");
foreach (var item in list)
Console.WriteLine(item);
Console.WriteLine();
You should get output like this:
List items:
123
456
789
Referenced value (original): 456
Referenced value (modified): 0
List items:
123
0
789
Collections don't work the same way in C# as they do in C++, for example you can add the same object to multiple different collections and so it doesn't really make sense to ask to get a reference to the list that an object is contained in, as it could be in many lists (or none, or even in the same list multiple times)
object myObject = new object();
List<object> list = new List<object>();
list.Add(myObject);
object[] someArray = new object[] { myObject };
Assert.AreEqual(list[0], someArray[0]);
If it helps you can think of lists in C# as being lists of pointers references to the objects being stored where the pointer itself is hidden from you, although understand that in reality the implementation may be more complicated (and is also irrelevant).
If there is a relationship between the objects in a list and the list contents of that list then its up to you to explicitly declare and keep track of what that realtionsip is, for example through a Parent property on the object in the list
List<T> myList = new List<T>();
// Whenever an item is added to myList set the Parent property
myList.Add(item);
item.Parent = myList;
This is what Windows Forms does in order to maintain the relationship between the controls in a container, and the container in which those controls are contained. Obviously you should decide what to do if someone tries to add the same object to multiple lists.
Not unless the type of abc[0] explicitly holds a reference to the list. In fact you cannot do that in C++ either without an explicit reference.
Think about it, in C++ if you can expect firstElemPtr == arrayPtr it is just because arrays store the elements that way and it only works for arrays; everything else is just by accident.
Now consider any list structure that allocates something else (maybe element count) before the pointer to the first element. Your assumption will not work anymore.
If you are designing the type of the items in the collection, then you can add a property to the item's type that "points" to the containing list; when you construct each item, pass in the containing list and save this in the property.
Something like this:
class ListItem
{
public List<ListItem> Parent { get; set; }
public ListItem(List<ListItem> parent)
{
Parent = parent;
}
}
ListItem listItem = new ListItem(abc);
abc.Add(listItem);
// Get collection from item.
List<T> def = listItem.Parent;
Consider:
unsafe static void Main() {
int[] arr = new int[100];
fixed(int* ptr = arr) {
// ptr is a pointer to the zeroth item in the array
}
}
However, unsafe code is not all that common in c# and should be limited to performance-critical regions (and even then used sparingly). In particular, note that we have "pinned" the array by doing this - and note that ptr is only reliable while it is pinned. Outside of the fixed block, GC is free to relocate the array, making ptr invalid.
Clarification: I don't suggest you should do this, but: such things are entirely possible.
List is defined somewhat like this:
public class List<T> : IList<T> blabla
{
private T [] data;
public T this[int index] {
get { return data[index]; }
set { data[index]=value; }
}
... blabla
}
YES, it is NOT linked list of any kind. So you must use it accordingly. Though since .NET value types are small and class types are all references, there usually no heavy array-copy operations as it is possible with C++ for example so such implementation of general-puprose collection is good enough (unless abused). Vector could be a better name from academic standpoint, but it's not.
You would not be able to get a reference to data array, as it's private variable. Nor you would have any need for this. If you need enumerator, use GetEnumerator explicitely or foreach for implicit use.

Store variables in list/array and loop through later c#

Sorry, I think I was not clear earlier. I am trying to do as O.R.mapper says below- create a list of arbitrary variables and then get their values later in foreach loop.
Moreover, all variables are of string type so I think can come in one list. Thanks.
Is there a way to store variables in a list or array then then loop through them later.
For example: I have three variables in a class c named x,y and Z.
can I do something like:
public List Max_One = new List {c.x,c.y,c.z}
and then later in the code
foreach (string var in Max_One)
{
if ((var < 0) | (var > 1 ))
{
// some code here
}
}
Is there a particular reason why you want to store the list of variables beforehand? If it is sufficient to reuse such a list whenever you need it, I would opt for creating a property that returns an IEnumerable<string>:
public IEnumerable<string> Max_One {
get {
yield return c.x;
yield return c.y;
yield return c.z;
}
}
The values returned in this enumerable would be retrieved only when the property getter is invoked. Hence, the resulting enumerable would always contain the current values of c.x, c.y and c.z.
You can then iterate over these values with a foreach loop as alluded to by yourself in your question.
This might not be practical if you need to gradually assemble the list of variables; in that case, you might have to work with reflection. If this is really required, please let me know; I can provide an example for that, but it will become more verbose and complex.
Yes, e.g. if they are all strings:
public List<string> Max_One = new List<string> {c.x,c.y,c.z};
This uses the collection initializer syntax.
It doesn't make sense to compare a string to an int, though. This is a valid example:
foreach (string var in Max_One)
{
if (string.IsNullOrEmpty(var))
{
// some code here
}
}
If your properties are numbers (int, for example) you can do this:
List<int> Max_One = new List<int> { c.x, c.y, c.Z };
and use your foreach like this
foreach(int myNum in Max_One) { ... } //you can't name an iterator 'var', it's a reserved word
Replace int in list declaration with the correct numeric type (double, decimal, etc.)
You could try using:
List<object> list = new List<object>
{
c.x,
c.y,
c.z
};
I will answer your question in reverse way
To start with , you cannot name your variable with "var" since it is reserved name. So what you can do for the foreach is
foreach (var x in Max_One)
{
if ((x< 0) || (x> 1 ))
{
// some code here
}
}
if you have .Net 3.0 and later framework, you can use "var" to define x as a member of Max_One list without worrying about the actual type of x. if you have older than the version 3.0 then you need to specify the datatype of x, and in this case your code is valid (still risky though)
The last point (which is the your first point)
public List Max_One = new List {c.x,c.y,c.z}
There are main thing you need to know , that is in order to store in a list , the members must be from the same datatype, so unless a , b , and c are from the same datatype you cannot store them in the same list EXCEPT if you defined the list to store elements of datatype "object".
If you used the "Object" method, you need to cast the elements into the original type such as:
var x = (int) Max_One[0];
You can read more about lists and other alternatives from this website
http://www.dotnetperls.com/collections
P.s. if this is a homework, then you should read more and learn more from video tutorials and books ;)

Categories