public class MyClass
{
public object Prop1 { get; set; }
public object Prop2 { get; set; }
public object Prop3 { get; set; }
}
Предположим , у меня есть объект myObject
из MyClass
и мне нужно сбросить свои свойства, что лучше создать новый объект или переназначить каждое свойство? Предположим, у меня нет никакого дополнительного использования со старым экземпляром.
myObject = new MyClass();
или
myObject.Prop1 = null;
myObject.Prop2 = null;
myObject.Prop3 = null;
c#
object-oriented
construction
Колокола
источник
источник
Suppose I have an object myObject of MyClass and I need to reset its properties
- Если требуется сброс свойств вашего объекта или если это полезно для моделирования проблемной области, почему бы не создатьreset()
метод для MyClass. См. Ответ HarrisonPaine нижеОтветы:
Создание нового объекта всегда лучше, тогда у вас есть 1 место для инициализации свойств (конструктор) и вы можете легко обновить его.
Представьте, что вы добавляете новое свойство в класс, вы скорее обновите конструктор, чем добавите новый метод, который также повторно инициализирует все свойства.
Теперь есть случаи, когда вы можете захотеть повторно использовать объект, когда свойство очень дорого переинициализируется, и вы захотите сохранить его. Однако это будет более специализированный метод, и у вас будут специальные методы для повторной инициализации всех других свойств. Вы все еще хотите создать новый объект иногда даже для этой ситуации.
источник
myObject = new MyClass(oldObject);
. Хотя это будет означать точную копию оригинального объекта в новом экземпляре.new MyClass(oldObject)
это лучшее решение для случаев, когда инициализация стоит дорого.Вы определенно должны предпочесть создание нового объекта в подавляющем большинстве случаев. Проблемы с переназначением всех свойств:
A
и классB
являются переданными экземплярами класса,C
они должны знать, будут ли им когда-либо передаваться один и тот же экземпляр, и если да, то другой ли он все еще использует. Это тесно связывает классы, которые в противном случае не имеют причин быть.Fraction
класс с числителем и знаменателем и хотели обеспечить, чтобы он всегда уменьшался (т. Е. Gcd числителя и знаменателя было 1). Это невозможно сделать красиво, если вы хотите разрешить людям устанавливать числитель и знаменатель публично, поскольку они могут переходить через недопустимое состояние, чтобы перейти из одного действительного состояния в другое. Например, 1/2 (действительный) -> 2/2 (недействительный) -> 2/3 (действительный).Это все довольно серьезные проблемы. И то, что вы получаете взамен за дополнительную работу, которую вы создаете, ... ничего. Создание экземпляров объектов, как правило, невероятно дешево, поэтому выигрыш в производительности почти всегда будет незначительным.
Как уже упоминалось в другом ответе, единственное время, которое может быть связано с эффективностью, - это если ваш класс выполняет довольно дорогостоящие работы по строительству. Но даже в этом случае, чтобы эта техника работала, вам нужно будет уметь отделять дорогостоящую деталь от свойств, которые вы сбрасываете, так что вы могли бы использовать вместо этого шаблон с наименьшим весом или аналогичный.
Как примечание, некоторые из вышеперечисленных проблем могут быть несколько смягчены, если не использовать сеттеры, а вместо этого иметь
public Reset
метод для вашего класса, который принимает те же параметры, что и конструктор. Если по какой-то причине вы захотите пойти по этому пути сброса, это, вероятно, будет гораздо лучшим способом сделать это.Тем не менее, дополнительная сложность и повторение, которые добавляют, наряду с пунктами выше, которые он не рассматривает, все еще являются очень убедительным аргументом против этого, особенно когда они сопоставляются с несуществующими преимуществами.
источник
Учитывая очень общий пример, трудно сказать. Если «сброс свойств» имеет смысл в случае домена, это будет более логично для потребителя вашего класса
чем
Я НИКОГДА не потребовал бы, чтобы потребитель вашего класса звонил
Если класс представляет что-то, что может быть сброшено, он должен предоставлять эту функциональность через
Reset()
метод, а не полагаться на вызов конструктора или ручную настройку его свойств.источник
Как предполагают Харрисон Пейн и Брандин, я бы повторно использовал один и тот же объект и стал бы факторизовать инициализацию свойств в методе Reset:
источник
Если предполагаемый шаблон использования класса состоит в том, что один владелец будет хранить ссылку на каждый экземпляр, никакой другой код не будет сохранять копии ссылок, и владельцы будут очень часто иметь циклы, которые должны много раз " заполните «пустой экземпляр», используйте его временно и никогда больше не понадобиться (общий класс соответствует такому критерию
StringBuilder
), тогда с точки зрения производительности может быть полезно включить в класс метод сброса экземпляра для новое состояние. Такая оптимизация вряд ли будет стоить много, если альтернатива потребует создания нескольких сотен экземпляров, но стоимость создания миллионов или миллиардов экземпляров объекта может сложиться.Относительно примечания, есть несколько шаблонов, которые можно использовать для методов, которые должны возвращать данные в объекте:
Метод создает новый объект; возвращает ссылку.
Метод принимает ссылку на изменяемый объект и заполняет его.
Метод принимает переменную ссылочного типа в качестве
ref
параметра и либо использует существующий объект, если это необходимо, либо изменяет переменную для идентификации нового объекта.Первый подход часто является самым простым семантически. Второе немного неудобно для вызывающей стороны, но может предложить лучшую производительность, если вызывающая сторона часто сможет создать один объект и использовать его тысячи раз. Третий подход немного неудобен семантически, но может быть полезен, если метод должен будет возвращать данные в массиве, и вызывающая сторона не будет знать требуемый размер массива. Если вызывающий код содержит единственную ссылку на массив, переписывание этой ссылки со ссылкой на больший массив будет семантически эквивалентно простому увеличению массива (что является желаемым поведением семантически). Хотя использование
List<T>
может быть более приятным, чем использование массива с ручным изменением размера во многих случаях, массивы структур предлагают лучшую семантику и лучшую производительность, чем списки структур.источник
Я думаю, что большинство людей, отвечающих за создание нового объекта, упускают критический сценарий: сборку мусора (GC). GC может значительно снизить производительность в приложениях, создающих множество объектов (например, в играх или научных приложениях).
Допустим, у меня есть дерево выражений, которое представляет математическое выражение, где во внутренних узлах находятся функциональные узлы (ADD, SUB, MUL, DIV), а конечные узлы являются терминальными узлами (X, e, PI). Если в моем классе узлов есть метод Evaluate (), он, вероятно, будет рекурсивно вызывать дочерние элементы и собирать данные через узел данных. По крайней мере, все конечные узлы должны будут создать объект данных, а затем их можно будет повторно использовать по пути вверх по дереву, пока не будет оценено окончательное значение.
Теперь предположим, что у меня есть тысячи таких деревьев, и я оцениваю их в цикле. Все эти объекты данных будут запускать GC и вызывать значительное снижение производительности (до 40% потери загрузки ЦП для некоторых запусков в моем приложении - я запустил профилировщик для получения данных).
Возможное решение? Повторно используйте эти объекты данных и просто вызовите некоторые .Reset () для них после того, как вы закончите использовать их. Листовые узлы больше не будут вызывать 'new Data ()', они будут вызывать некоторый метод Factory, который обрабатывает жизненный цикл объекта.
Я знаю это, потому что у меня есть приложение, которое решило эту проблему, и это решило ее.
источник