Or K
Or K

Reputation: 335

The list doesn't change in a method C#

I have a class Items, and I try to sort a list of items:

private static void Sort(List<Items> items)
{
.
.
.
   SortDesc(items);
}

private static void SortDesc(List<Items> items)
{
  items = items.OrderByDescending(x => x.Neto).ToList();
}

When the debugger in SortDesc(), the items in the list are sorted by Neto DESC. When I continue and return back to Sort(), the list in back to how it was before I called SortDesc().

The List<T> sending by default by ref, so why does this not work?

Thanks!

Upvotes: 0

Views: 518

Answers (4)

Jeppe Stig Nielsen
Jeppe Stig Nielsen

Reputation: 62002

The List<T> sending by default by ref, so why does this not work?

No, all parameters that are not specially marked, are passed by value (and it goes for both reference types and value types). If you changed your method into ref it would work:

private static void SortDesc(ref List<Items> items)
{
  items = items.OrderByDescending(x => x.Neto).ToList();
}

The point here, as was also explained in Farhad's answer, is that .ToList() creates a new instance of List<Items>. The old instance is unchanged. The assignment items = ... above changes the value of the reference (from referring the original instance to referring the new instance), so if the parameter is by value it will not work.

Since you make a new instance, it is probably better to just return it directly:

private static List<Items> SortDesc(List<Items> items)
{
  return items.OrderByDescending(x => x.Neto).ToList();
}

However, since you made your method void, maybe you wanted to sort the same list and not create another list?

In that case there are some possibilities. One is to use the Sort method on List<>, like this:

private static void SortDesc(List<Items> items)
{
  items.Sort((x, y) => y.Neto.CompareTo(x.Neto)); // unstable
}

or:

private static void SortDesc(List<Items> items)
{
  items.Sort((x, y) => Comparer<Xxx>.Default.Compare(y.Neto, x.Neto)); // unstable
}

where Xxx denotes the declared (compile-time) type of the Neto property. The first (simpler) of these two works fine if .Neto is never a null reference (including the case where Xxx is a value type).

These are descending because we swap x and y after the lambda arrow.

Warning: Unstable means that if some Items in the List<> have equally small .Neto, there is no telling what the order of these is going to be. This is not equivalent to the earlier examples which are stable.

If you need Linq OrderByDescending or need stable sort, you might try the following (although it is not pretty):

private static void SortDesc(List<Items> items)
{
  var tempList = items.OrderByDescending(x => x.Neto).ToList();
  items.Clear();
  items.AddRange(tempList);
}

Instead of Clear and AddRange you can also copy the list entries explicitly with a for loop containing items[i] = tempList[i].

Upvotes: 0

Farhad Jabiyev
Farhad Jabiyev

Reputation: 26655

You are changing the reference in memory which the items is pointing with this line of code:

 items = items.OrderByDescending(x => x.Neto).ToList();

When you are calling the SortDesc method, list object is passed by reference. And then you are creating new list. After this you are setting it to items parameter. After this, items is pointing to the new reference, not the previous one. But, the real items is still pointing to the old one.

So, you must return newly created list:

private static List<Items> SortDesc(List<Items> items)
{
  return items.OrderByDescending(x => x.Neto).ToList();
}

And then, just set it in your Sort method:

items = SortDesc(items);

P.S: You can also use ref keyword explicitly for the desired result, but this is not the preferred way actually. (...void SortDesc(ref List<Items> items)). You can read @JonSkeet answer from his answer to that question When to use ref and when it is not necessary in C#:

Useful answer: you almost never need to use ref/out. It's basically a way of getting another return value, and should usually be avoided precisely because it means the method's probably trying to do too much.

Upvotes: 6

Enigmativity
Enigmativity

Reputation: 117134

When you call SortDesc you pass a copy of the reference to the original items variable to the method. So in the method when you re-assign item you are assigning the new reference to a copy of the original reference and not the original reference itself. The original reference stays the same.

In order to update the original reference you need to pass items by reference. Do it like this:

private static void SortDesc(ref List<Items> items)
{
    items = items.OrderByDescending(x => x.Neto).ToList();
}

If you do it that way the call would become SortDesc(ref items). This will work as expected.

Upvotes: 0

Sajeetharan
Sajeetharan

Reputation: 222682

You need to return the ordered items,

private static  List<Items>  SortFromTheHighPriceToLowPriceByNeto(List<Items> items)
{
    items = items.OrderByDescending(x => x.Neto).ToList();
    return items;
}

Upvotes: 1

Related Questions