Passing an object to a method and then calling an extenstion method on that object
I was working on a method yesterday and ran into something strange, here is dumbed down version of the code: Basically the problem is that the OrderBy applied in the Bar.PopulateList method is not persisting.
class Foo
{
List MyObjects;
public void PopulateMyObjects()
{
//Items are added to my list but the OrderBy is not persisting.
Bar.PopulateList(MyObjects);
}
}
class Bar
{
public static int PopulateList(List theList)
{
foreach(var in WebSerbiceCall)
{
theList.Add(var);
}
// the OrderBy call only sorts 'theList' in the context of this method.
// When I return from this method theList 开发者_如何学Gohas been populated but the Ordering has
// reverted back to the order that the items were added to the list.
theList.OrderBy(obj => obj.ID);
return theList.Count;
}
}
Now if I update the code and add the ref keyword as per below it all works: e.g. public static int PopulateList(ref List theList) and Bar.PopulateList(ref MyObjects);
Can anyone enlighten me? I thought objects were always passed by ref? Is it the fact that OrderBy is an extension method?
Thanks, Cian
The problem here is that the OrderBy
call does not actually mutate theList
in any way. It instead returns a new IEnumerable<object>
which is ordered. Hence this is why you do not see the affects of the call outside the method, it's simply not changing the object.
Using the OrderBy
method creates a new value and hence if you want the calling function to be aware of this new value it must be returned in some manner. The most common places are in the return value or in a ref
/out
param.
public static int PopulateList(ref List<object> theList) {
...
theList = theList.OrderBy(obj => obj.ID).ToList();
}
Try:
return theList.OrderBy(obj => obj.ID).Count;
(I was going to add an explaination but @jaredPar has explained it)
C# passes arguments by value, it's just that the value of a reference type is the pointer to it's memory location. The problem you are having is this line:
theList.OrderBy(obj => obj.ID);
You're not assigning the result:
theList = thisList.OrderBy(obj => obj.ID).ToList();
The Enumerable.OrderBy extension method does not sort the List<T> in-place. It returns an IEnumerable<T> that returns the elements of the list in sorted order.
Use the List<T>.Sort method to sort the List<T> in-place.
If you don't use the ref
keyword then the parameter passed is a new reference to the same object. It is 'passed by reference' in a sense but you have to think about it a bit differently.
Other answers are correct, OrderBy
does not perform in place and instead returns an ordered collection. But if you set your parameter to the result, then you change the value of the parameter (the reference) to point to the new collection, rather than changing the underlying object itself.
For example,
theList = thisList.OrderBy(obj => obj.ID).ToList();
takes theList
, orders it and then creates a new List. Then the value of theList
- which is a reference to a list - is changed to point to the newly created (ordered) list. The original reference, created outside this method, still points to the original unordered list.
The reason is that whenever you call .ToList()
you actually create a new list. When you use the ref
keyword, you pass the actual variable containing the reference to the list, rather than create a new reference to the same list.
精彩评论