What happens to the List content? - c#

I have a list, defined as a global in the base class:
private List<Object> progObjs;
In the constructor of a derived class I have:
Object newObj = new Object();
this.progObjs = new List<Object>();
this.progObjs.Add(newObj);
Adding a break point after this shows that the object has gone into the list, and the list is of now Count = 1.
However, in another function in the class, I attempt to use the first object in the list (i.e. progObjs[0]), but it throws a NullReferenceException and the list is actually Count = 0, even though I haven't removed the object from the list myself.
What has happened to the object in my list?
Thanks,
Mitch.

Found the problem:
I'm working with XNA, and the base class's Initialize method was resetting the list after the derrived class defined it.

Related

2 Generic list assignment

if class type list is there named
Collection<PurchaseOrderDetail> poDetails = new Collection<PurchaseOrderDetail>();
and another list with same type is there named _poH.PODetail
why _poH.PODetail = poDetails.ToList(); generates an error
Cannot implicitly convert type 'System.Collections.Generic.List'
to 'System.Collections.ObjectModel.Collection'
what is the solution for this, any explanation please.
All the reason behind the question is
_poH.PODetail = poDetails;
made poDetails.RemoveAt(Convert.ToInt32(e.RowIndex)); updates as well so I was searching for some thing like _poH.PODetail = poDetails.ToCollection();
According to the error message, _poH.PODetail is of type Collection, so assigning a list to it doesn’t work. But since poDetails is a collection itself, you can just assign it directly:
poH.PODetail = poDetails;
So you don’t actually need to call ToList() on it to convert it to a list.
There is no ToCollection method you could call on enumerables, but you could use the Collection constructor that takes a list to make it wrap that list and create a readonly collection:
new Collection(poDetails.ToList());
The short answer is simply that the ToList<T> extension returns an instance of List<T> class which, although similar, is not the same type as Collection<T>.
Basically this doesn't work for the same reasons you cannot set a string value to an integer variable.
One thing you can do though, is initializing the content of a new collection instance with an IList<T> instance. Therefore, the following should give you exactly what you want:
_poH.PODetail = new Collection(poDetails.ToList());
Also, as poke suggested, you might also want to assign the PODetail property with the poDetails variable itself.
_poH.PODetail = poDetails;
However, you must remember that Collection<T> is a reference type. This means that the objects in your collection won't be "copied" inside _poH.PODetail; instead, both poDetails and _poH.PODetail will be pointing to the exact same collection. Any changes done to one collection will automatically be reflected on the other.

Duplicate an ObservableCollection Item

I want to duplicate a list item in an observablecollection. When I do:
TreasureCards[TreasureCards.Count - 1] = TreasureCards[CardPosition];
It creates a copy of the specific list item but then they are linked in my UI. So if I change the new duplicated item's name, it changes the originals name. I know I could do each of the properties one by one (see below) but is there a way to just copy the entire item?
TreasureCards[TreasureCards.Count - 1].Name = TreasurecCards[CardPosition].Name;
TreasureCards[TreasureCards.Count - 1].Type= TreasurecCards[CardPosition].Type;
// etc
You aren't duplicating the object. You're creating a new reference to the object. There's still only one object; now there are two references to it in your collection, and any change to the object is reflected by both references.
To create a new object, you can call MemberwiseClone() on anything that derives from Object. This method returns a new instance, copying the values from all fields in the original object. So you'd do:
TreasureCards[TreasureCards.Count - 1] = TreasureCards[CardPosition].MemberwiseClone();
There are two limitations with this method. First, it's a shallow copy, i.e. any reference fields in the original object have their values copied. So if a.Foo is a reference to a Bar object, a.MemberwiseClone().Foo will refer to the same Bar object. Second, the method just copies the fields; it doesn't call the new object's constructor. Depending on the design of the class, this is either unimportant or a Really Big Deal.
Usually, it's safer to make the class implement ICloneable and explicitly implement a Clone() method, e.g.:
public TreasureCard Clone()
{
return new TreasureCard
{
Name = this.Name,
Type = this.Type,
...
};
}
They aren't linked, they are the same instance. All you're doing is copying a reference to the same data to another position in the array.
What you need to do is implement some Clone method that makes a copy of the original instance but as another instance. This SO post might help.
Then you would do something like this:
TreasureCards[TreasureCards.Count - 1] = TreasureCards[CardPosition].Clone();

List passed by ref - help me explain this behaviour

Take a look at the following program:
class Test
{
List<int> myList = new List<int>();
public void TestMethod()
{
myList.Add(100);
myList.Add(50);
myList.Add(10);
ChangeList(myList);
foreach (int i in myList)
{
Console.WriteLine(i);
}
}
private void ChangeList(List<int> myList)
{
myList.Sort();
List<int> myList2 = new List<int>();
myList2.Add(3);
myList2.Add(4);
myList = myList2;
}
}
I assumed myList would have passed by ref, and the output would
3
4
The list is indeed "passed by ref", but only the sort function takes effect. The following statement myList = myList2; has no effect.
So the output is in fact:
10
50
100
Can you help me explain this behavior? If indeed myList is not passed-by-ref (as it appears from myList = myList2 not taking effect), how does myList.Sort() take effect?
I was assuming even that statement to not take effect and the output to be:
100
50
10
Initially, it can be represented graphically as follow:
Then, the sort is applied myList.Sort();
Finally, when you did: myList' = myList2, you lost the one of the reference but not the original and the collection stayed sorted.
If you use by reference (ref) then myList' and myList will become the same (only one reference).
Note: I use myList' to represent the parameter that you use in ChangeList (because you gave the same name as the original)
You are passing a reference to the list, but your aren't passing the list variable by reference - so when you call ChangeList the value of the variable (i.e. the reference - think "pointer") is copied - and changes to the value of the parameter inside ChangeList aren't seen by TestMethod.
try:
private void ChangeList(ref List<int> myList) {...}
...
ChangeList(ref myList);
This then passes a reference to the local-variable myRef (as declared in TestMethod); now, if you reassign the parameter inside ChangeList you are also reassigning the variable inside TestMethod.
Here is an easy way to understand it
Your List is an object created on heap. The variable myList is a
reference to that object.
In C# you never pass objects, you pass their references by value.
When you access the list object via the passed reference in
ChangeList (while sorting, for example) the original list is changed.
The assignment on the ChangeList method is made to the value of the reference, hence no changes are done to the original list (still on the heap but not referenced on the method variable anymore).
This link will help you in understanding pass by reference in C#.
Basically,when an object of reference type is passed by value to an method, only methods which are available on that object can modify the contents of object.
For example List.sort() method changes List contents but if you assign some other object to same variable, that assignment is local to that method. That is why myList remains unchanged.
If we pass object of reference type by using ref keyword then we can assign some other object to same variable and that changes entire object itself.
(Edit: this is the updated version of the documentation linked above.)
C# just does a shallow copy when it passes by value unless the object in question executes ICloneable (which apparently the List class does not).
What this means is that it copies the List itself, but the references to the objects inside the list remain the same; that is, the pointers continue to reference the same objects as the original List.
If you change the values of the things your new List references, you change the original List also (since it is referencing the same objects). However, you then change what myList references entirely, to a new List, and now only the original List is referencing those integers.
Read the Passing Reference-Type Parameters section from this MSDN article on "Passing Parameters" for more information.
"How do I Clone a Generic List in C#" from StackOverflow talks about how to make a deep copy of a List.
While I agree with what everyone has said above. I have a different take on this code.
Basically you're assigning the new list to the local variable myList not the global.
if you change the signature of ChangeList(List myList) to private void ChangeList() you'll see the output of 3, 4.
Here's my reasoning...
Even though list is passed by reference, think of it as passing a pointer variable by value
When you call ChangeList(myList) you're passing the pointer to (Global)myList. Now this is stored in the (local)myList variable. So now your (local)myList and (global)myList are pointing to the same list.
Now you do a sort => it works because (local)myList is referencing the original (global)myList
Next you create a new list and assign the pointer to that your (local)myList. But as soon as the function exits the (local)myList variable is destroyed.
HTH
class Test
{
List<int> myList = new List<int>();
public void TestMethod()
{
myList.Add(100);
myList.Add(50);
myList.Add(10);
ChangeList();
foreach (int i in myList)
{
Console.WriteLine(i);
}
}
private void ChangeList()
{
myList.Sort();
List<int> myList2 = new List<int>();
myList2.Add(3);
myList2.Add(4);
myList = myList2;
}
}
Use the ref keyword.
Look at the definitive reference here to understand passing parameters.
To be specific, look at this, to understand the behavior of the code.
EDIT: Sort works on the same reference (that is passed by value) and hence the values are ordered. However, assigning a new instance to the parameter won't work because parameter is passed by value, unless you put ref.
Putting ref lets you change the pointer to the reference to a new instance of List in your case. Without ref, you can work on the existing parameter, but can't make it point to something else.
There are two parts of memory allocated for an object of reference type. One in stack and one in heap. The part in stack (aka a pointer) contains reference to the part in heap - where the actual values are stored.
When ref keyword is not use, just a copy of part in stack is created and passed to the method - reference to same part in heap. Therefore if you change something in heap part, those change will stayed. If you change the copied pointer - by assign it to refer to other place in heap - it will not affect to origin pointer outside of the method.

error: Object reference not initialised

I have the following code in C#:
IList<string> myList = null;
myList.Add(temp);
temp is a string that is decalred elsewhere and is not null (I checked it). I keep getting the following error at the line myList.Add(temp); "Object reference not initialised to an instance of an object"
What am I doing wrong here???
Updating the quesiton: I have already tried new
IList<string> myList = new List<string>();
as most of you suggested andget the following from Intellisense:
Cannot create an instance of the abstract class or interface Systems.Collections.Generic.Ilist.
Thanks for your previous answers. Now I am running into a peculiar problem. My datareader has an empty string in it. (1 field in the sql server table is blank. that is string.Empty). Is there a way to get rid of this inside the reader (I mean rdr here)??
you need to initialize the list first:
IList<string> myList = new List<string>();
...
Please note that on the right of = you have to write List<string> not IList<string> since IList<string> is an interface, whereas List<string> is a class that implements that interface.
The line:
IList<string> myList = null;
does not give you a list, but an empty reference to where a list could be.
IList<string> myList = new List<string>();
would properly instantiate myList, so you can use it (Add, Remove, etc.).
Here, take a look at this tutorial to better understand variable initialization.
From http://www.csharphelp.com/2007/03/objects-classes-in-c/
Person Michael = new Person();
In the first line of code we specified integer variablecalled age. In the second line we specified first the type of Object we need tocreate followed by the object’s name followed by a reserved operator called new and we end by typing the class name again followed byparenthesis “()”.
Let’s understand it step-by-step. Specifying the class nameat the beginning tell the C# Compiler to allocate a memory location for thattype (C# compiler knows all the variables and properties and methods of theclass so it will allocate the right amount of memory). Then we followed theclass name by out object variable name that we want it. The rest of the code”=new Person();” callthe object’s constructor. We will talk about constructor later but for nowunderstand that the constructor is a way to initialize your object’s variablewhile you are creating it not after you create it. For example, The Michaelobject we created it in the last section can be written as following :
Person Michael = new Person(20, “Brown”);
here I specified the variable’s values in the parameter listso I initialized the variables while I’m creating the object. But for this codeto work we will need to specify the constructor in the Person class and I willnot do that here because constructor section will come in later articles. Ithink you got a good introduction about Classes and Objects not I will completein in my next article and I will talk about constructors and building blockscoping. I hope you got a new thing from my article.
Updating the quesiton: I have already tried new Ilist() as most of you suggested andget the following from Intellisense: Cannot create an instance of the abstract class or interface Systems.Collections.Generic.Ilist
You cannot create instances of an Interface. IList<T> is an interface. Like the others have said here you initialize it with an instance of a concrete class that inherits the interface. Notice how they use new List<String>() not new IList<String>();
IList<String> items = new List<String>();

problem adding object to hashtable

I am trying to call a class method dynamically depending on a condition. This is how I am doing it
I have three classes implement a single interface
interface IReadFile
{
string DoStuff();
}
The three classes A,B,C implement the interface above.
I am trying to add them to a hashtable with the code below
_HashT.Add("a", new classA());
_HashT.Add("b", new classB());
_HashT.Add("c", new classC());
This compiles fine, but gives a runtime error.{Object reference not set to an instance of an object.}
I was planning to return the correct class to the interface type depending on a parameter that matches the key value. say if I send in a. ClassA is returned to the interface type and the method is called.
IReadFile Obj = (IReadFile )_HashT["a"].GetType();
obj.DoStuff();
How do I correct the part above where the objects need to be added to the hashtable? Or do I need to use a different approach? All the classes are in the same assembly and namespace.
Thanks for your time.
As a guess, you have not instantiated your _HashT object.
You need somewhere in your code (declaration or constructor probably) to instantiate it:
HashTable _HashT = new HashTable();
If you do not do this, _HashT will be null and an attempt to add to it will fail with a NullReferenceException as you have been getting.
It appears you are seeing a NullReferenceException. Based on the limited code you provided I would say it is likely that the _HashT variable is not assigned. It could be possible that the exception is being generated from one of your class constructors as well.
If you use Dictionary<> you can use the following code to add and extract objects from the hashtable.
var hashtable = new Dictionary<IReadFile>();
hashtable.Add("a", new ClassA());
hashtable.Add("b", new ClassB());
hashtable.Add("c", new ClassC());
IReadFile obj = hashtable["a"];
obj.DoStuff();
Following your approach, you do not need to call GetType() on the value you pull out of _HashT. The value should already be an object of type IReadFile.
Why are you calling GetType? The IReadFile object is the thing you are putting in the hash. Casting a Type object into a IReadFile is not going to cast correctly.

Categories

Resources