Nasıl değişmez bir Sınıf oluşturabilirim?


113

Değişmez bir sınıf yaratmak için çalışıyorum.
Tüm özellikleri salt okunur olarak işaretledim.

Sınıftaki öğelerin bir listesi var.
Özellik salt okunur olsa da liste değiştirilebilir.

Listenin IEnumerable'ını açığa çıkarmak onu değişmez kılar.
Bir sınıfı değişmez kılmak için uyulması gereken temel kuralların ne olduğunu bilmek istedim.


2
Eric Lippert'in değişmezlik hakkındaki blog dizisini, özellikle de "değişmezlik türleri" hakkındaki girişini okumanızı şiddetle tavsiye ederim . "Listenin IEnumerable'ını açığa çıkarmak onu değişmez yapar" yorumunuz bana biraz tuhaf geliyor. Bununla ne demek istiyorsun?
Jon Skeet

Demek istediğim, listeye erişime izin vermekten ziyade (nesne başka nesnelerin bir listesine sahipse), kullanıcının IEnumerable ile üyelere erişmesine izin vermekti. Belirli bir örnekte olduğu gibi burada konuşma listesi, ancak herhangi bir veri yapısı olabilir.
Biswanath

1
MSDN bu blogları arşivlediğinde Jon Skeet'in Eric Lippert'in blog dizisine olan bağlantıları koptu. Lütfen "değişmezlik türleri" ne bakın . Serinin geri kalanı sol panelde Aralık 2007 + Ocak 2008 altında görünüyor.
John Doe

İnsanlar genellikle terimleri karıştırmayın nasıl Eric Lippert blog serisi bakınız atomicity, volatilityve immutability: Birinci Bölüm , İkinci Bölüm ve Bölüm Üç . Bunlar kişisel blogundan ve bence MSDN gönderilerinden daha yeni kullanıcı dostu.
John Doe

Yanıtlar:


121

Bence doğru yoldasın -

  • sınıfa enjekte edilen tüm bilgiler kurucuda sağlanmalıdır
  • tüm özellikler yalnızca alıcılar olmalıdır
  • yapıcıya bir koleksiyon (veya Dizi) geçirilirse, arayanın onu daha sonra değiştirmesini önlemek için kopyalanmalıdır.
  • Koleksiyonunuzu iade edecekseniz, ya bir kopyasını ya da salt okunur bir sürümünü iade edin (örneğin, ArrayList.ReadOnly veya benzerini kullanarak - bunu bir önceki nokta ile birleştirebilir ve bir salt okunur kopyasını saklayabilirsiniz . arayanlar buna erişir), bir numaralandırıcı döndürür veya koleksiyona salt okunur erişime izin veren başka bir yöntem / özellik kullanır
  • Üyelerinizden herhangi biri değiştirilebilirse, yine de değiştirilebilir bir sınıf görünümüne sahip olabileceğinizi unutmayın - bu durumda, saklamak isteyeceğiniz durumu kopyalamanız ve kopyalamadığınız sürece tüm değişken nesneleri geri döndürmekten kaçınmanız gerekir. onları arayan kişiye geri vermeden önce - başka bir seçenek de değiştirilebilir nesnenin yalnızca değişmez "bölümlerini" geri vermektir - @ Brian Rasmussen sayesinde beni bu noktayı genişletmeye teşvik ettiği için

Yalnızca bakmanızı sağlayan bir sarmalayıcı arama özelliği yazmalı mıyım? Ve cevap için teşekkürler.
Biswanath

5
Yapıcıya bağımsız değişken olarak iletilen herhangi bir değiştirilebilir başvuru türü kopyalanmalıdır. Aksi takdirde arayan kişi yine de duruma bir referans tutacaktır.
Brian Rasmussen

@Brian Rasmussen, haklısın, ancak kopyalanmış olsa bile, sağlanan erişimlere bağlı olarak herhangi bir arayanın değiştirilebilir nesneye erişmesi mümkün olabilir. Değişken bir nesnenin aktarılması durumunda, sınıfın her zaman farklı bir kopyasını veya nesnenin değişmez bölümlerini döndürmesi en iyisidir
Blair Conrad

@Blair - Sınıfta sadece arama için kullanmak istediğim sözlüğüm varsa. Arama yapan salt okunur bir özellik iyi olmalı mı?
Biswanath

@Biswanath - evet, eğer sözlükteki değerler değişebilirse, mutasyona uğramasını istemiyorsanız, geri dönmeden önce onları korumanız gerektiği uyarısıyla
Blair Conrad

18

Değişmez olmak için, tüm özellikleriniz ve alanlarınız salt okunur olmalıdır. Ve herhangi bir listedeki öğeler de değişmez olmalıdır.

Aşağıdaki gibi salt okunur bir liste özelliği oluşturabilirsiniz:

public class MyClass
{
    public MyClass(..., IList<MyType> items)
    {
        ...
        _myReadOnlyList = new List<MyType>(items).AsReadOnly();
    }

    public IList<MyType> MyReadOnlyList
    {
        get { return _myReadOnlyList; }
    }
    private IList<MyType> _myReadOnlyList

}

1
ImmutableList'in daha iyi olacağını düşünüyorum.
Kevin Wong

ImmutableList'i kullanın, ayrıca sınıfı mühürlemeyi de düşünün
kofifus

Ben ImmutableList bu kullanım şeklini iyi bir uyum olduğunu ikna olmadım: basic rules to make a class (that contains a list) immutable. ImmutableList semantiği, listenin bir kopyasına öğeler eklerken daha verimli bellek kullanımı sağlar, ancak bu bana daha özel bir kullanım durumu gibi görünüyor.
Joe

11

Ayrıca şunları unutmayın:

public readonly object[] MyObjects;

salt okunur anahtar sözcüğüyle işaretlenmiş olsa bile değişmez değildir. Yine de dizin erişimcisine göre tek tek dizi referanslarını / değerlerini değiştirebilirsiniz.


5

ReadOnlyCollectionSınıfı kullanın . System.Collections.ObjectModelAd alanında yer alır .

Listenizi (veya yapıcıda) döndüren herhangi bir şeyde, listeyi salt okunur bir koleksiyon olarak ayarlayın.

using System.Collections.ObjectModel;

...

public MyClass(..., List<ListItemType> theList, ...)
{
    ...
    this.myListItemCollection= theList.AsReadOnly();
    ...
}

public ReadOnlyCollection<ListItemType> ListItems
{
     get { return this.myListItemCollection; }
}

1

Başka bir seçenek de, herhangi bir dahili koleksiyonun tamamını sergilemek yerine bir ziyaretçi kalıbı kullanmaktır.


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.