Reputation: 9460
I have a C# class that does some parsing of XML passed in to its one public method. The idea is that the method pulls info out of the XML, creates objects and sets up collections of them in public properties...
public class XmlParser {
public List<Customer> Customers { get; set; }
public void ProcessXml(string xml) {
XElement data = XElement.Parse(xml);
CreateEntities(Customers, data);
// do other stuff...
}
}
This way, we can do things like this in the calling code...
XmlParser xp = new XmlParser();
xp.ProcessXml(xml);
// do something with xp.Customers
I am trying to write a private generic method in the parser class, which would be used by the ProcessXml() method, and save me writing boilerplate code over and over again. The beginning of this method looks like this (other parameters missed out for clarity)...
private void CreateEntities<T>(List<T> collection, XElement data) {
if (collection == null) {
collection = new List<T>();
}
// process the XElement passed in, and add objects to the collection
}
I'm trying to use it like this...
CreateEntities(Customers, data);
...where the other parameters allow the compiler to know the generic type, and allow the method to know which entities to create etc.
However, the problem I have is that whilst the method itself works fine, and the collection variable is populated correctly, the public Customers property remains null.
I thought that passing a reference type, such as a List<> to a method allowed the method to modify the type, and have those changes seen outside the method, like in the answer from recursive in this SO post (I know that's a Dictionary, but I would have thought the principle would be the same).
Howcome my method can set collection to a new List<>, but Customers (which is the same object) remains null?
Update: Sigh, I ought to learn to read error messages!
Before I posted my question, I had tried passing the collection by ref, and it gave me compiler errors. I obviously didn't pay enough attention to the messages before moving on to plan B.
Having read the replies here, I tried ref again, and spotted that the compiler error was because I was trying to pass a public property by ref, which is not allowed. I changed the property from an automatic one to one with a backing field, passed the backing field by ref and it all works fine!
Upvotes: 0
Views: 283
Reputation: 1502016
I thought that passing a reference type, such as a List<> to a method allowed the method to modify the type, and have those changes seen outside the method
You're getting confused with passing a parameter by reference (using the ref
modifier), and passing a reference by value.
When you pass the value of a reference type (e.g. List<Customer>
) to a method, you're still passing that argument by value by default. You can change the contents of the object that the variable's value refers to, but you can't change which object the original argument referred to, which is what you're trying to do.
Think about it like this... if I hand someone a piece of paper with my home address on, then they can do two things:
I will be able to see the result of the first action - it's changing something about the house itself. I won't be able to see the result of the second action, because it's just changing what's on the piece of paper... which is just a copy of what I know to be my home address.
For more details, refer to my article on parameter passing in C#.
To fix your problem, I would just change your CreateEntities
method to return a list, rather than accepting one:
private List<T> CreateEntities<T>(XElement data)
{
var list = new List<T>();
// Populate the list...
return list;
}
If the caller wants to add those to an existing list, they can do so easily.
Upvotes: 3
Reputation: 1361
I think you missing the passing reference type by using ref. For more information ref (C# Reference)
Upvotes: 2