AddRange () не работает при добавлении элементов списка в коллекцию - PullRequest
0 голосов
/ 28 марта 2019

Недавно я получил задание для работы с одним из предупреждений FxCop - Не открывать общие списки . Поэтому я попытался изменить List<T> на ICollection<T>. Но позже, во время модульного тестирования, я обнаружил, что AddRange() не работает должным образом, как ожидалось. Он не добавляет коллекцию элементов в объект коллекции.

Вот пример кода

gc.ToList().AddRange(sampleList);

И у меня есть два вопроса, чтобы задать

  1. Почему это не добавление предметов в коллекцию. Ниже приведен код:

    public class GenericClass
    {
        public int Id;
        public string Name;
    }  
    
    
    class Program
    {
         static void Main(string[] args)
         {
    
          ICollection<GenericClass> gc = new  List<GenericClass>();
    
        var sampleList = new List<GenericClass>()
                             {
                                 new GenericClass {Id = 1, Name = "ASD"},
                                 new GenericClass {Id = 2, Name = "QWER"},
                                 new GenericClass {Id = 3, Name = "BNMV"},
                             };
    
        Console.WriteLine(gc.GetType()); // gc is of type
    
        gc.ToList().AddRange(sampleList); // sampleList items are not getting added to gc.
        Console.ReadKey();
    }
    

    }

  2. List<T> наследуется от ICollection<T>, а List<T> имеет функции AddRange() и т. Д. Когда я пытался привести к родительской ссылке (ICollection<T>) на объект дочернего класса (List<T>), почему Intellisense не предлагает AddRange(). Вместо этого мне нужно сделать .ToList(), а затем он показывает AddRange(). Screenshot

Я много искал это. Но не смог найти причину, которая меня удовлетворила. Поэтому, пожалуйста, помогите мне с пониманием. Это будет отличная помощь.

Ответы [ 2 ]

2 голосов
/ 28 марта 2019

Метод AddRange() работает нормально.Проблема в том, что вы не внимательно прочитали документацию по методу расширения ToList() и поэтому не понимаете, что метод ToList() возвращает совершенно новый объект .

Из документации :

Создает список из IEnumerable .

Поскольку объект, который вы вызываете AddRange() фактически это не оригинальная коллекция, оригинальная коллекция остается неизменной.

В некотором смысле, ваш вопрос List<T> эквивалентен очень распространенному вопросу "почему не работает string.Replace()?"

В приведенном вами примере нет лучшего решения, чем просто не скрывать List<T>.Вы можете, поскольку вы используете общий интерфейс ICollection<T>, написать свой собственный AddRange() в качестве метода расширения:

public static void AddRange<T>(this ICollection<T> collection, IEnumerable<T> range)
{
    foreach (T t in range)
    {
        collection.Add(t);
    }
}

Но я не уверен, что это действительно намного лучше, чем просто оставитьвведите как List<T>, если цель состоит в том, чтобы иметь возможность изменять объект и использовать метод AddRange().

Приведение ссылки ICollection<T> обратно к ее основному List<T> (как предлагает другой ответчик)) бессмысленно, так как это в первую очередь сведет на нет любое значение при использовании интерфейса ICollection<T>.

Просто оставьте ссылку как List<T>, по крайней мере, в любом контексте, где вам действительно нужно изменитьколлекция.(Хорошо, и даже, возможно, полезно, выставить этот список в других контекстах, используя только ICollection<T>, но это совершенно другое обсуждение.)

Пока я отвечаю, я буду упоминать, что яСкептически относимся к тому, что вы правильно поняли цель предупреждения FxCop, поскольку раскрытие общих списков само по себе не является вредным.

1 голос
/ 28 марта 2019

ToList() возвращает новый экземпляр, поэтому вы не можете увидеть результат AddRange в "gc".Если вы действительно хотите использовать AddRange, вы можете сделать следующее.

((List<GenericClass>)gc).AddRange(sampleList);
...