Предотвращение дублирования массива
-
03-07-2019 - |
Вопрос
Согласно [MSDN:Рекомендации по использованию массива](http://msdn.microsoft.com/en-us/library/k2604h5s (VS.71).aspx):
Свойства, оцениваемые по массиву
Вы должны использовать коллекции, чтобы избежать неэффективности кода.В следующем примере кода каждый вызов свойства myObj создает копию массива.В результате в следующем цикле будет создано 2n+1 копия массива.
[Visual Basic]
Dim i As Integer
For i = 0 To obj.myObj.Count - 1
DoSomething(obj.myObj(i))
Next i
[C#]
for (int i = 0; i < obj.myObj.Count; i++)
DoSomething(obj.myObj[i]);
Кроме изменения с myObj[] на ICollection myObj, что еще вы бы порекомендовали?Только что понял, что в моем текущем приложении происходит утечка памяти:(
Спасибо;
Редактировать:Улучшит ли принуждение C # передавать ссылки без ссылки (помимо безопасности) производительность и / или использование памяти?
Решение
Нет, это не так протекающий память - это просто заставляет сборщик мусора работать усерднее, чем он мог бы.На самом деле, статья MSDN немного вводит в заблуждение:если свойство создало новый Коллекция каждый раз, когда он вызывался, это было бы так же плохо (с точки зрения памяти), как и в случае с массивом.Возможно, что еще хуже, из-за обычного завышения размеров большинства реализаций коллекций.
Если вы знаете, что метод / свойство действительно работает, вы всегда можете минимизировать количество вызовов:
var arr = obj.myObj; // var since I don't know the type!
for (int i = 0; i < arr.Length; i++) {
DoSomething(arr[i]);
}
или еще проще, используйте foreach
:
foreach(var value in obj.myObj) {
DoSomething(value);
}
Оба подхода вызывают свойство только один раз.Второе понятнее, ИМО.
Другие мысли;назовите это методом!т. е. obj.SomeMethod()
- это устанавливает ожидания того, что это действительно сработает, и позволяет избежать нежелательных obj.Foo != obj.Foo
(что было бы справедливо для массивов).
Наконец, у Эрика Липперта есть хороший статья на эту тему.
Другие советы
Просто в качестве подсказки для тех, кто еще не использовал ReadOnlyCollection, упомянутый в некоторых ответах:
[C#]
class XY
{
private X[] array;
public ReadOnlyCollection<X> myObj
{
get
{
return Array.AsReadOnly(array);
}
}
}
Надеюсь, это может помочь.
Всякий раз, когда у меня есть дорогостоящие свойства (например, воссоздание коллекции по вызову) Я либо документирую свойство, указывая, что каждый вызов сопряжен с затратами, либо кэширую значение как частное поле.Средства получения свойств, которые являются дорогостоящими, должны быть записаны как методы.Как правило, я стараюсь предоставлять коллекции как IEnumerable, а не массивы, заставляя потребителя использовать foreach (или перечислитель).
Он не будет создавать копии массива, если вы не заставите его сделать это.Однако простая передача ссылки на массив, находящийся в частной собственности объекта, имеет некоторые неприятные побочные эффекты.Тот, кто получает ссылку, в принципе, волен делать с массивом все, что ему заблагорассудится, включая изменение содержимого способами, которые не могут контролироваться его владельцем.
Одним из способов предотвращения несанкционированного вмешательства в массив является возврат копии содержимого.Другой (немного лучший) способ - вернуть коллекцию, доступную только для чтения.
Тем не менее, прежде чем делать что-либо из вышеперечисленного, вы должны спросить себя, не собираетесь ли вы выдать слишком много информации.В некоторых случаях (на самом деле, довольно часто) даже лучше сохранить массив закрытым и вместо этого позволить предоставлять методы, которые работают с объектом, владеющим им.
myobj не создаст новый элемент, если вы явно его не создадите.поэтому, чтобы лучше использовать память, я рекомендую использовать частную коллекцию (список или любую другую) и использовать индексатор, который вернет указанное значение из частной коллекции