将对象传递给方法,然后在该对象上调用扩展方法

时间:2010-12-02 00:22:20

标签: c# extension-methods linq-to-objects byref

昨天我正在研究一种方法并遇到一些奇怪的问题,这里是代码版本的愚蠢:基本上问题是在Bar.PopulateList方法中应用的OrderBy不会持久存在。


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 has 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;
   }
}

现在,如果我更新代码并按照下面的方式添加ref关键字,则所有工作都有效: 例如public static int PopulateList(ref List theList) 和Bar.PopulateList(ref MyObjects);

任何人都可以开导我吗?我以为对象总是通过ref传递? OrderBy是一种扩展方法吗?

谢谢,Cian

5 个答案:

答案 0 :(得分:4)

这里的问题是OrderBy调用实际上并没有以任何方式改变theList。它改为返回一个新的IEnumerable<object>,它是有序的。因此,这就是为什么你没有看到方法之外的调用的影响,它只是不改变对象。

使用OrderBy方法创建一个新值,因此如果您希望调用函数知道这个新值,则必须以某种方式返回它。最常见的地方是返回值或ref / out参数。

public static int PopulateList(ref List<object> theList) {
  ...
  theList = theList.OrderBy(obj => obj.ID).ToList();
}

答案 1 :(得分:1)

尝试:

return theList.OrderBy(obj => obj.ID).Count;

(我打算补充说明,但是@jaredPar解释了它)

答案 2 :(得分:1)

C#按值传递参数,只是引用类型的值是指向它的内存位置的指针。你遇到的问题是这一行:

theList.OrderBy(obj => obj.ID);

您没有分配结果:

theList = thisList.OrderBy(obj => obj.ID).ToList();

答案 3 :(得分:1)

Enumerable.OrderBy扩展方法未对就地List<T>进行排序。它返回一个IEnumerable<T>,它按排序顺序返回列表的元素。

使用List<T>.Sort method对就地List<T>进行排序。

答案 4 :(得分:0)

如果不使用ref关键字,则传递的参数是对同一对象的新引用。在某种意义上它是“通过引用传递”,但你必须对它有所不同。

其他答案都是正确的,OrderBy没有执行,而是返回有序集合。但是,如果将参数设置为结果,则将参数(引用)的值更改为指向新集合,而不是更改基础对象本身。

例如,

theList = thisList.OrderBy(obj => obj.ID).ToList();

获取theList,对其进行排序,然后创建一个新的List。然后,theList的值 - 它是对列表的引用 - 被更改为指向新创建的(有序)列表。在此方法之外创建的原始引用仍指向原始无序列表。

原因是无论何时拨打.ToList(),您实际上都会创建一个新列表。当您使用ref关键字时,将传递包含对列表的引用的实际变量,而不是创建对同一列表的新引用。