Как передать значение по ссылке в C #? - PullRequest
1 голос
/ 29 января 2010

У меня есть следующий код linq.

searchResults = (from item1 in searchResults
              join item2 in coll
              on item1.skuID equals item2.Skuid
              where item2.SearchableValue == value
              select item1).ToList();

Переменная searchResults передается в методе как общий список. Сегмент linq выше фильтрует список. Когда я вернусь из метода, я ожидаю, что список будет изменен, но ссылка осталась неизменной, поскольку она была передана. Как мне добиться изменения моей ссылки, а не копии? Спасибо.

Ответы [ 5 ]

12 голосов
/ 29 января 2010

Вы должны вернуть отфильтрованный результат, поэтому, если ваш метод выглядит следующим образом:

public void Filter(List<Item> searchResults)

изменить на:

public IEnumerable<Item> Filter(List<Item> searchResults)

и затем возвращает результат вместо присвоения его переменной. Другими словами, измените это:

searchResults = (from item1 in searchResults

к этому:

return (from item1 in searchResults

В вашем вызове измените с:

Filter(list)

до:

list = Filter(list).ToList();

Это дает вам максимальное повторное использование, так как вы можете передать список и довериться методу, который не изменит его, оставляя за вами выбор: поместить его в новую переменную или заменить исходный список.

Кроме того, как указал Фредрик в его комментариях, вызов .ToList() в запросе Linq также должен быть удален, и, возможно, вы захотите изменить также входной параметр на IEnumerable.

Позвольте мне подвести итог.

Если у вас есть такой код:

public void Filter(List<Item> searchResults)
{
    searchResults = (from item1 in searchResults
                     join item2 in coll
                     on item1.skuID equals item2.Skuid
                     where item2.SearchableValue == value
                     select item1).ToList();
}

...
list = ...
Filter(list);

и хочу сделать list обновленным, я бы изменил код так:

       __ changed ______        __ changed ______
public IEnumerable<Item> Filter(IEnumerable<Item> searchResults)
{
    return from item1 in searchResults               <-- changed
           join item2 in coll
           on item1.skuID equals item2.Skuid
           where item2.SearchableValue == value
           select item1;                             <-- changed
}

...
list = ...         _ added__
list = Filter(list).ToList();
7 голосов
/ 29 января 2010

Я вижу, у вас уже есть ответ на ваш вопрос. Но вам может быть любопытно, почему вы не можете использовать параметр ref в понимании запроса.

Причина в том, что выражение понимания запроса представляет запрос , а не его результаты . Он представляет отложенное выполнение запроса. Итак, предположим, что мы допустили, что:

IEnumerable<int> Frob(ref int x)
{  return from foo in whatever where foo.bar == x select foo.bar; }

IEnumerable<int> Blob()
{ 
    int y = 123; 
    var r = Frob(ref y);    
    y = 456;
    return r;
}
void Grob()
{
    foreach(int z in Blob()) { ... }
}

Что это делает? Запрос не выполняется до тех пор, пока Blob не вернется, но запрос ссылается на ссылку на локальную переменную в кадре, который больше не существует.

Компилятор не может знать, что вы не в этой ситуации каждый раз, когда в запросе используется ссылка, поэтому он полностью ее запрещает.

4 голосов
/ 29 января 2010

Вы назначаете параметр searchResults для указания на новый экземпляр List.

Чтобы увидеть изменение в вызывающем методе, вам нужно сделать его параметром ref.

Кроме того, вы можете изменить список на месте, например так:

var newResults = (from item1 in searchResults
                  join item2 in coll
                  on item1.skuID equals item2.Skuid
                  where item2.SearchableValue == value
                  select item1).ToArray();

searchResults.Clear();
searchResults.AddRange(newResults);
2 голосов
/ 29 января 2010

Вам необходимо пометить параметр searchResults как ref.

public void Foo(ref List<T> searchResults) { ... }

Редактировать

Поскольку вы используете список в запросе (который является анонимным методом), вам придется изменить список на месте, а не параметр ref.

var results = (from item1 in searchResults
               join item2 in coll
               on item1.skuID equals item2.Skuid
               where item2.SearchableValue == value
               select item1).ToList();

searchResults.Clear();
searchResults.AddRange(results);

Похоже, Слакс получил этот ответ быстрее.

0 голосов
/ 29 января 2010

Переменная searchResults должна быть передана как параметр [ref][1].

Подпись метода будет выглядеть следующим образом.

//Note you only need to ref the one variable.
void filter(ref List searchResults, object otherParameter)
{
   //LINQ and stuff here
}

Чтобы позвонить, вам также нужно использовать ref:

filter(ref myResults, stuff);
...