Yeni nesne oluştur veya her özellik sıfırlansın mı?


29
 public class MyClass
    {
        public object Prop1 { get; set; }

        public object Prop2 { get; set; }

        public object Prop3 { get; set; }
    }

Ben bir nesne var varsayalım myObjectait MyClassve ben özelliklerini sıfırlamak gerekir, her özellik yeni bir nesne oluşturmak veya yeniden atamak için daha iyidir? Eski örnek ile herhangi bir ek kullanımım olmadığını varsayalım.

myObject = new MyClass();

veya

myObject.Prop1 = null;
myObject.Prop2 = null;
myObject.Prop3 = null;


14
Bağlam olmadan gerçekten cevaplanamaz.
KodlarInChaos

2
@CodesInChaos, gerçekten. Yeni nesneler yaratmanın tercih edilemeyeceği belirli bir örnek: Nesne Havuzlaması ve GC ile başa çıkmak için tahsisleri en aza indirmeye çalışmak.
XNargaHuntress

@ XGundam05 Fakat o zaman bile, OP'de önerilen bu tekniğin onunla başa çıkmanın uygun yolu olması pek olası değil
Ben Aaronson,

2
Suppose I have an object myObject of MyClass and I need to reset its properties- Nesnenizin özelliklerini sıfırlamanız gerekiyorsa veya sorunlu etki alanını modellemede reset()fayda varsa , neden Sınıfım için bir yöntem oluşturmuyorsunuz . Aşağıdaki HarrisonPaine cevabına bakınız
Brandin

Yanıtlar:


49

Yeni bir nesneyi başlatmak her zaman iyidir, o zaman özellikleri (kurucu) başlatmak için 1 yeriniz vardır ve onu kolayca güncelleyebilirsiniz.

Sınıfa yeni bir özellik eklediğinizi düşünün, yapıcıyı tüm özellikleri de yeniden başlatan yeni bir yöntem eklemek yerine güncellemeyi tercih edersiniz.

Şimdi, bir nesneyi yeniden kullanmak isteyebileceğiniz, bir özelliğin yeniden başlatmak için çok pahalı olduğu ve onu saklamak isteyebileceğiniz durumlar vardır. Ancak bu daha uzman olurdu ve diğer tüm özellikleri yeniden başlatmak için özel yöntemlere sahip olacaksınız. Hala bu durum için bile yeni bir nesne oluşturmak istersiniz.


6
Muhtemel Üçüncü seçenek: myObject = new MyClass(oldObject);. Bununla birlikte, bu, yeni bir örnekte orijinal nesnenin tam bir kopyasını ima edecektir.
AmazingDreams

Ben new MyClass(oldObject)başlatma pahalı olduğu durumlarda en iyi çözüm olduğunu düşünüyorum .
rickcnagy

8
Kopya kurucuları daha C ++ tarzıdır. .NET, tam bir kopya olan yeni bir örnek döndüren bir Clone () yönteminden yana görünüyor.
Eric

2
İnşaatçı kolayca hiçbir şey yapamaz, kamuya açık bir Initialize () yöntemini çağırır, bu nedenle hala etkin bir şekilde "yeni" yeni bir nesne oluşturmak için herhangi bir noktaya çağrılabilecek tek bir başlatma noktasına sahip olursunuz. Nesne havuzlarında kullanılabilecek ve performans için yeniden kullanılabilecek nesneler için IInitialize arabirimi gibi bir kütüphaneye sahip oldum.
Chad Schouggins

16

Kesinlikle yeni bir nesne oluştururken tercih etmelidir engin Vakaların çoğunda. Tüm özellikleri yeniden atama ile ilgili sorunlar:

  • Sağlayabileceğiniz kapsülleme seviyesini büyük ölçüde sınırlayan tüm mülklerde genel belirleyiciler gerektirir
  • Eski durum için herhangi bir ek kullanımınız olup olmadığını bilmek, eski durumun kullanıldığı her yerde bilmeniz gereken anlamına gelir. Eğer sınıf Ave sınıf Bher ikisi de sınıfın örneklerinden geçti ise, Co zaman aynı örneğe geçip geçmeyeceklerini ve eğer öyleyse diğerinin hala onu kullanıp kullanmadığını bilmek zorundadırlar. Bu, başka türlü olması gerekmeyen sınıfları sıkıca birleştiriyor.
  • Gbjbaanb'ın belirtildiği gibi, tekrarlayan kodlara yol açar, eğer kurucuya bir parametre eklerseniz, kurucuyu çağıran her yerde derleme başarısız olur, bir noktanın kaybolma tehlikesi yoktur. Genel bir özellik eklerseniz, nesnelerin "sıfırlandığı" her yeri manuel olarak bulup güncellediğinizden emin olmanız gerekir.
  • Karmaşıklığı arttırır. Döngüde sınıfın bir örneğini oluşturduğunuzu ve kullandığınızı hayal edin. Metodunuzu kullanıyorsanız, o zaman şimdi döngüden ilk kez veya döngü başlamadan önce ayrı başlatma yapmanız gerekir. Her iki durumda da, bu iki başlatma yolunu desteklemek için yazmanız gereken ek koddur.
  • Yani, sınıfınız kendini geçersiz bir durumda olmaktan koruyamaz. FractionBir pay ve payda ile bir sınıf yazdığınızı ve bunun her zaman düşürüldüğünü zorlamak istediğinizi düşünün (yani pay ve paydaşın toplamı 1 idi). İnsanların pay ve paydayı herkese açık olarak belirlemelerine izin vermek istiyorsanız, geçersiz bir durumdan bir geçerli durumdan diğerine geçebilecekleri için, bunu güzelce yapmak imkansızdır. 1/2 (geçerli) -> 2/2 (geçersiz) -> 2/3 (geçerli).
  • Çalıştığınız dil için aptalca değil, kodu koruyan herkes için bilişsel sürtünmeyi arttırıyor.

Bunların hepsi oldukça önemli problemler. Ve yarattığınız ekstra iş karşılığında elde ettiğiniz şey ... hiçbir şey. Nesne örnekleri oluşturmak genel olarak inanılmaz derecede ucuzdur, bu nedenle performans yararı neredeyse her zaman tamamen göz ardı edilebilir olacaktır.

Bahsedilen diğer cevabın da belirtildiği gibi, tek zaman performansının, sınıfınızın inşaat üzerinde önemli ölçüde pahalı işler yapması ile ilgili bir endişe kaynağı olabilir. Ancak bu durumda bile, bu tekniğin çalışması için, pahalı parçayı sıfırladığınız özelliklerden ayırmanız gerekir, böylece bunun yerine uç ağırlık kalıbı veya benzerini kullanabilirsiniz .


Bir yan not olarak, yukarıdaki sorunlardan bazıları ayarlayıcı kullanmadan ve bunun yerine public Resetsınıfınızda yapıcı ile aynı parametreleri alan bir yöntem kullanarak hafifletilebilir . Herhangi bir nedenden dolayı, bu sıfırlama yolundan aşağıya inmek isteseydiniz, bu muhtemelen bunu yapmanın çok daha iyi bir yolu olurdu.

Yine de, üzerinde durmadığı noktalarla birlikte ekleyen karmaşıklık ve tekrarlama, özellikle varolmayan faydalara karşı tartıldığında, buna karşı hala çok ikna edici bir argümandır.


Yeni bir nesne oluşturmak yerine sıfırlamak için çok önemli bir kullanım durumunun, nesneyi gerçekten sıfırlıyor olmanız olduğunu düşünüyorum. IE. nesneye işaret eden diğer sınıfların sıfırladıktan sonra yeni bir nesne görmesini istiyorsanız.
Taemyr

@ Taemyr Muhtemelen, ancak OP açıkça soruya aykırı davranıyor
Ben Aaronson

9

Çok genel bir örnek verildiğinde, bunu söylemek zor. "Özelliklerin sıfırlanması", etki alanı için anlamsal bir anlam ifade ediyorsa, sınıfınızın tüketicisi aramak için daha mantıklı olacaktır.

MyObject.Reset(); // Sets all necessary properties to null

göre

MyObject = new MyClass();

ASLA sınıf aramanızın tüketicisini yapmak istemem

MyObject.Prop1 = null;
MyObject.Prop2 = null; // and so on

Sınıf, sıfırlanabilecek bir şeyi temsil ediyorsa, bu işlevi Reset(), yapıcıyı çağırmak veya özelliklerini elle ayarlamak yerine bir yöntemle göstermelidir .


5

Harrison Paine ve Brandin'in önerdiği gibi, aynı nesneyi tekrar kullanır ve bir Reset yönteminde özelliklerin başlatılmasını faktörleştirir:

public class MyClass
{
    public MyClass() { this.Reset() }

    public void Reset() {
        this.Prop1 = whatever
        this.Prop2 = you name it
        this.Prop3 = oh yeah
    }

    public object Prop1 { get; set; }

    public object Prop2 { get; set; }

    public object Prop3 { get; set; }
}

Aynen cevaplamak istediğim şeydi. Bu, her iki dünyanın da en iyisidir - Ve kullanım durumuna bağlı olarak, tek uygun seçenek (Örnek Havuzu)
Falco

2

Bir sınıf için amaçlanan kullanım şekli, tek bir sahibin her bir örneğe referans tutacağıysa, başka hiçbir kod referansların kopyalarını tutamaz ve sahiplerin defalarca ihtiyaç duyan döngülere sahip olmaları çok yaygın olacaktır. " "boş bir örneği doldurun, geçici olarak kullanın ve bir daha asla ihtiyaç duymayın (böyle bir ölçütle yapılan ortak bir sınıf toplantısı olur StringBuilder) o zaman sınıf açısından bir örneği sıfırlamak için bir yöntem eklemek için performans açısından yararlı olabilir. yeni durum. Böyle bir optimizasyon, alternatifin yalnızca birkaç yüz örnek oluşturmayı gerektiriyorsa, buna değmeyebilir, ancak milyonlarca veya milyarlarca nesne örneği oluşturma maliyeti toplanabilir.

İlgili bir notta, bir nesnede veri döndürmesi gereken yöntemler için kullanılabilecek birkaç desen vardır:

  1. Yöntem yeni nesne oluşturur; referansı döndürür.

  2. Yöntem değiştirilebilir bir nesneye başvuru kabul eder ve onu doldurur.

  3. Yöntem, bir referans tipi değişkeni refparametre olarak kabul eder ve uygunsa mevcut nesneyi kullanır veya yeni bir nesneyi tanımlamak için değişkeni değiştirir.

İlk yaklaşım çoğu zaman anlamsal olarak en kolay olanıdır. İkincisi, arayan tarafında biraz gariptir, ancak arayan bir kişinin sık sık bir nesne oluşturması ve onu binlerce kez kullanması durumunda daha iyi performans sunabilir. Üçüncü yaklaşım anlamsal olarak biraz gariptir, ancak bir yöntemin bir dizide veri döndürmesi gerekecek ve arayan kişi gerekli dizi boyutunu bilmeyecekse yararlı olabilir. Çağıran kod dizinin tek referansını tutarsa, bu başvuruyu daha büyük bir diziye referansla yeniden yazmak, diziyi daha büyük hale getirmek için anlamsal olarak eşdeğer olacaktır (bu, istenen davranışı semantiktir). Kullanım List<T>, çoğu durumda manuel olarak yeniden boyutlandırılmış bir dizi kullanmaktan daha güzel olabilirken, yapı dizileri, yapı listelerinden daha iyi anlamsallık ve daha iyi performans sunar.


1

Yeni bir nesne yaratmayı tercih edenlerin çoğunun kritik bir senaryo eksik olduğunu düşünüyorum: çöp toplama (GC). GC, birçok nesne yaratan uygulamalarda (düşünce oyunları veya bilimsel uygulamalar) gerçek bir performansa sahip olabilir.

Diyelim ki iç düğümlerde fonksiyon düğümleri (ADD, SUB, MUL, DIV) ve yaprak düğümleri terminal düğümleri (X, e, PI) olan matematiksel bir ifadeyi temsil eden bir ifade ağacım var. Düğüm sınıfım bir Evaluate () yöntemine sahipse, büyük olasılıkla çocukları tekrar tekrar arayacak ve bir Veri düğümü aracılığıyla veri toplayacaktır. En azından, tüm yaprak düğümlerinin bir Data nesnesi yaratması gerekecektir ve daha sonra bunlar nihai değer değerlendirilene kadar ağacın yolunda tekrar kullanılabilirler.

Şimdi diyelim ki bu ağaçlardan binlerce tane var ve onları bir döngü halinde değerlendiriyorum. Tüm bu Data nesneleri bir GC'yi tetikleyecek ve performans çarpmasına neden olacak, büyük bir tane (benim uygulamamda bazı çalışmalar için% 40'a varan CPU kullanım kaybı - verileri almak için bir profil oluşturucu koştum).

Muhtemel bir çözüm? Bu veri nesnelerini yeniden kullanın ve kullandıktan sonra üzerlerindeki bazı .Reset () öğelerini çağırın. Yaprak düğümleri artık 'new Data ()' demeyecek, nesnenin yaşam döngüsünü ele alan bazı Fabrika yöntemlerini arayacaklar.

Bunu biliyorum çünkü bu sorunu çözen bir uygulamam var ve bu sorunu çözdü.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.