2010-06-24 4 views
33

В .NET Framework многие классы System.Collection имеют методы Clear. Есть ли явное преимущество при использовании этого вместо замены ссылки на новый объект?Использование метода «clear» и New Object

Спасибо.

+0

Возможный дубликат [Каковы основные различия между Dictionary.clear и новым Dictionary() в C#?] (Http://stackoverflow.com/questions/1400532/what-are-the-key-differences-between- dictionary-clear-and-new-dictionary-in-c) – nawfal

ответ

39

Вы хотите использовать Clear, если у вас есть другие ссылки на один и тот же объект, и вы хотите, чтобы все они указывали на один и тот же объект.

Возможно, у вас есть рабочая очередь, где хранятся задачи. И в одном или нескольких потоках вы берете рабочие элементы из этой очереди (конечно, вы используете блокировку, чтобы убедиться, что вы обращаетесь к очереди с не более чем одним потоком за раз). Если в какой-то момент вы хотите очистить очередь, тогда вы можете использовать Clear, и все потоки будут по-прежнему указывать на один и тот же объект.

Как seen here при использовании Clear все элементы будут удалены, а Count будет 0, но Capacity останется неизменным. Обычно Capacity не меняется, это хорошая вещь (для эффективности), но может быть какой-то крайний случай, когда у вас было много предметов, и вы хотите, чтобы память была в конечном итоге освобождена.

В приведенной выше ссылке MSDN упоминается, что Clear является операцией O (n). Если просто заменить ссылку будет операция O (1), а затем, в конце концов, это будет сбор мусора, но, возможно, не сразу. Но замена ссылки также означает, что память, которая составляет емкость, должна быть перераспределена.

+2

Это получило большую часть, единственное, что я хочу добавить, это то, что вы хотите использовать Clear при работе с ObservableCollections, которые просматриваются уже. – Rangoric

3

замена ссылки не выпустит коллекцию сразу, что нужно будет ждать, пока сборщик мусора расположить объект,

если вы хотите повторно использовать один и тот же объект коллекции использование ясно, если вы не будете иметь два объектов в памяти в течение некоторого времени.

+0

Хотя это правда, это не та разница, о которой заботятся большинство людей. –

+0

@ Игнасио Васкес-Абрамс зависит. Мне было бы очень интересно, если коллекция очень большая. – nawfal

6

Brian является правильным, но, если быть более конкретным, метод Clear удаляет все элементы из текущего экземпляра коллекции. Создание экземпляра новой коллекции и присвоение ее ссылки на вашу переменную даст вам совершенно новый экземпляр в целом и может привести к некоторым непредвиденным последствиям в зависимости от того, ссылаются ли другие люди на старый экземпляр. Если в другом потоке есть ссылка на эту коллекцию, они все равно будут содержать ссылку на старую коллекцию, даже если вы создали новый экземпляр.

3

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

1

Новый объект вызывает проблемы с памятью, если вы работаете с большими данными и часто используете элемент IEnumerable. Посмотрите на мой пример:

class Lol 
{ 
    int i; 
    string s; 
    public Lol(int ti, string ts) 
    { 
     i = ti; 
     s = ts; 
    } 
} 

class Program 
{ 
    static List<Lol> lol = new List<Lol>(); 

    static void Main(string[] args) 
    { 
     for (int i = 0; i < 10000000; ++i) 
      lol.Add(new Lol(i, i.ToString())); 

     Stopwatch sw = new Stopwatch(); 
     sw.Start(); 
     ListCleaner(); 
     sw.Stop(); 
     Console.WriteLine(sw.ElapsedMilliseconds); 

     for (int i = 0; i < 10000000; ++i) 
      lol.Add(new Lol(i, i.ToString())); 

     Console.WriteLine("lol"); 

     ListCleaner(); 

     for (int i = 0; i < 10000000; ++i) 
      lol.Add(new Lol(i, i.ToString())); 

     Console.WriteLine("lol"); 

     ListCleaner(); 

     for (int i = 0; i < 10000000; ++i) 
      lol.Add(new Lol(i, i.ToString())); 

     Console.WriteLine("lol"); 

     ListCleaner(); 

     for (int i = 0; i < 10000000; ++i) 
      lol.Add(new Lol(i, i.ToString())); 

     Console.WriteLine("lol"); 

     ListCleaner(); 

     for (int i = 0; i < 10000000; ++i) 
      lol.Add(new Lol(i, i.ToString())); 

     Console.WriteLine("lol"); 

     ListCleaner(); 

     for (int i = 0; i < 10000000; ++i) 
      lol.Add(new Lol(i, i.ToString())); 

     Console.WriteLine("lol"); 

     ListCleaner(); 

     for (int i = 0; i < 10000000; ++i) 
      lol.Add(new Lol(i, i.ToString())); 

     Console.WriteLine("lol"); 

     ListCleaner(); 

     for (int i = 0; i < 10000000; ++i) 
      lol.Add(new Lol(i, i.ToString())); 

     Console.WriteLine("lol"); 

     ListCleaner(); 
    } 

    static void ListCleaner() 
    { 
     //lol = new List<Lol>(); 
     lol.Clear(); 
    } 
} 

Если вы используете это, вы не столкнетесь с какой-либо проблемой во время выполнения. Но если вы прокомментируете строку «Очистить» в ListCleaner и раскомментируете новую линию объектов, у вас будет проблема с памятью.

Кстати, «Console.WriteLine (sw.ElapsedMilliseconds)»; (Вы можете использовать ElapsedTicks, потому что его значение сильно отличается от другого.) Строка говорит вам, что Clear занимает больше времени, но экономит вас от проблемы с памятью.

Я заметил, что все это происходит на отладочном коде (даже для режима выпуска). Нет проблем с запуском .exe-файла.

Смежные вопросы