Bir alanı C # 'da' salt okunur 'olarak işaretlemenin faydaları nelerdir?


295

Üye değişkenin salt okunur olarak bildirilmesinin faydaları nelerdir? Sadece sınıfın yaşam döngüsü boyunca birisinin değerini değiştirmesine karşı mı koruma sağlıyor yoksa bu anahtar kelimeyi kullanmak herhangi bir hız veya verimlilik artışı sağlıyor mu?


8
İyi dış cevap: dotnetperls.com/readonly
OneWorld

3
İlginç. Bu aslında bu Java sorusunun C # eşdeğeri stackoverflow.com/questions/137868/… Burada tartışma çok daha az ısıtılır ... hmm ...
RAY

7
O belirterek değerinde olabilir readonlyyapı tiplerinin alanları herhangi bir üyesi çağırma beri, sadece mutasyona uğramış değildir değişken alanları ile karşılaştırıldığında performans kaybı oluşturabilir readonlyalanın bir kopyasını yapmak için derleyici neden olacaktır değer tipi alan ve çağırmak üye.
supercat

2
performans cezası hakkında daha fazla bilgi: codeblog.jonskeet.uk/2014/07/16/…
CAD bloke

Yanıtlar:


171

readonlyAnahtar zamanında hesaplanır değer bir üye değişkeni sabit bildirmek için kullanılır, ancak olanak tanır. Bu, constdeğiştiriciyle bildirilen ve değerini derleme zamanında ayarlaması gereken bir sabitten farklıdır . Kullanarak readonlyalanın değerini ya bildirimde ya da alanın üyesi olduğu nesnenin yapıcısında ayarlayabilirsiniz.

Ayrıca, sabiti referans alan harici DLL'leri yeniden derlemek istemiyorsanız da kullanın (derleme zamanında değiştirildiği için).


193

Salt okunur bir alan kullanmanın herhangi bir performans kazancı olduğuna inanmıyorum. Nesne tamamen oluşturulduktan sonra, bu alanın yeni bir değere işaret edilemediğinden emin olmak sadece bir kontroldür.

Bununla birlikte, "salt okunur" diğer salt okunur semantik türlerinden çok farklıdır, çünkü çalışma zamanında CLR tarafından uygulanır. Salt okunur anahtar kelime, CLR tarafından doğrulanabilen .initonly olarak derlenir.

Bu anahtar kelimenin gerçek avantajı değişmez veri yapıları oluşturmaktır. Değişmez veri yapıları tanım gereği oluşturulduktan sonra değiştirilemez. Bu, bir yapının çalışma zamanında davranışı hakkında mantık yürütmeyi çok kolaylaştırır. Örneğin, değişmez bir yapının kodun başka bir rastgele bölümüne geçme tehlikesi yoktur. Bu yapıya karşı güvenilir bir şekilde programlayabilmeniz için değiştiremezler.

İşte değişmezliğin faydalarından biri hakkında iyi bir giriş: Diş çekme


6
Bunu okursanız, stackoverflow.com/questions/9860595/… salt okunur üye değiştirilebilir ve .net tarafından tutarsız bir davranışa benziyor
Akash Kava

Lütfen yukarıdaki İş Parçacığı hakkındaki yazının bağlantısını güncelleyebilir misiniz? Kırılmış.
Akshay Khot

69

Kullanmanın belirgin bir performans avantajı readonlyyok, en azından hiçbir yerde bahsettiğim kadarıyla gördüm. Tam olarak önerdiğiniz gibi yapmak, başlatıldıktan sonra modifikasyonu önlemek içindir.

Bu nedenle, daha sağlam, daha okunabilir bir kod yazmanıza yardımcı olması açısından faydalıdır. Bunun gibi şeylerin gerçek yararı, bir ekipte çalışırken veya bakım için gelir. readonlyBir değişkenin kodda kullanımı için bir sözleşme koymaya benzer bir şey beyan etmek. Bunu, internalveya diğer anahtar kelimelerle aynı şekilde belge eklemek olarak düşünün veya private"bu değişken başlatıldıktan sonra değiştirilmemelidir" diyorsunuz ve dahası, bunu zorunlu kılıyorsunuz .

Bir sınıf oluşturursanız ve bazı üye değişkenleri readonlytasarıma göre işaretlerseniz , kendinizin veya başka bir takım üyesinin daha sonra sınıfınızı genişlettiklerinde veya sınıfınızı değiştirdiklerinde hata yapmasını önlersiniz. Benim düşünceme göre, bu, görülmeye değer bir faydadır (yorumlarda doofledorfer'den bahsedildiği gibi ekstra dil karmaşıklığı küçük bir maliyetle).


Ve otoh dili basitleştirir. Ancak, fayda beyanınızı reddetmemek.
dkretz

3
Kabul ediyorum, ancak sanırım gerçek fayda, kod üzerinde birden fazla kişi çalışırken geliyor. Kod içinde küçük bir tasarım ifadesine sahip olmak, kullanımı için bir sözleşme gibi. Muhtemelen cevaba koymalıyım hehe.
Xiaofu

7
Bu cevap ve tartışma aslında bence en iyi cevap +1
Jeff Martin

@Xiaofu: Beni bu dünyadaki hiç kimsenin en akılcı zihni anlayamadığını açıklayan hahaha güzel açıklaması fikrinden sürekli kıldın
Öğrenci

Yani kodunuzda bu değerin hiçbir zaman değişmemesi gerektiği konusunda niyetiniz var.
Andez

51

Çok pratik terimlerle ifade etmek gerekirse:

Eğer const dll A ve dll B referanslarında bir const kullanırsanız, bu const değeri dll B derlenir. Eğer dll A bu const için yeni bir değerle yeniden konuşlandırırsanız, dll B hala orijinal değeri kullanıyor olacaktır.

Eğer salt okunur dll A ve dll B referanslarında bir salt okunur kullanırsanız, bu salt okunur her zaman çalışma zamanında aranacaktır. Bu, dll A'yı salt okunur değer için yeni bir değerle yeniden dağıtırsanız, dll B'nin bu yeni değeri kullanacağı anlamına gelir.


4
Bu farkı anlamak için iyi bir pratik örnektir. Teşekkürler.
Shyju

Öte yandan, constperformans artışı üzerinde olabilir readonly. İşte kod ile biraz daha derin bir açıklama: dotnetperls.com/readonly
Dio Phung

2
En büyük pratik terimin bu cevapta eksik olduğunu düşünüyorum: çalışma zamanında hesaplanan değerleri readonlyalanlara depolama yeteneği . Bir kaydedemezsiniz new object();bir de constve bu tür kimliğini değiştirmeden derleme sırasında diğer derlemeler içine referans olarak sigara değer şeyler pişirmek olamaz çünkü mantıklı.
binki

14

Derleyicinin salt okunur anahtar kelimenin varlığına bağlı olarak performans optimizasyonu yapabileceği olası bir durum vardır.

Bu yalnızca salt okunur alan aynı zamanda statik olarak işaretlenmişse de geçerlidir . Bu durumda, JIT derleyicisi bu statik alanın asla değişmeyeceğini varsayabilir. JIT derleyicisi, sınıfın yöntemlerini derlerken bunu dikkate alabilir.

Tipik örnek: sınıfınızda yapıcıda başlatılan statik bir salt okunur IsDebugLoggingEnabled alanı olabilir (örneğin bir yapılandırma dosyasına dayalı olarak). Gerçek yöntemler JIT derlendiğinde, hata ayıklama günlüğü etkinleştirilmediğinde derleyici kodun tüm bölümlerini ommitleyebilir.

Bu optimizasyonun aslında JIT derleyicisinin geçerli sürümünde uygulanıp uygulanmadığını kontrol etmedim, bu yüzden bu sadece spekülasyon.


bunun için bir kaynak var mı?
Sedat Kapanoglu

4
Mevcut JIT derleyicisi aslında bunu uygular ve CLR 3.5'ten beri vardır. github.com/dotnet/coreclr/issues/1079
mirhagk

Salt okunur alanların salt okunur değil readwrite olmasının basit bir nedeni olarak salt okunur alanlarda hiçbir optimizasyon yapılamaz. Çoğu derleyicinin saygı duyduğu bir derleyici ipucudur ve salt okunur alanların değerlerinin yansımayla kolayca üzerine yazılabilir (kısmen güvenilir kodda olmasa da).
Christoph

9

Salt okunur değerin yalnızca değerin kendisi için geçerli olduğunu unutmayın, bu nedenle salt okunur bir referans türü kullanıyorsanız, başvuruyu yalnızca değişiklikten korur. Örneğin durumu salt okunur tarafından korunmaz.


4

Params readonlykullanarak herhangi bir kurucu dışında alanları ayarlamak için bir geçici çözüm olduğunu unutmayın out.

Biraz dağınık ama:

private readonly int _someNumber;
private readonly string _someText;

public MyClass(int someNumber) : this(data, null)
{ }

public MyClass(int someNumber, string someText)
{
    Initialise(out _someNumber, someNumber, out _someText, someText);
}

private void Initialise(out int _someNumber, int someNumber, out string _someText, string someText)
{
    //some logic
}

Burada daha fazla tartışma: http://www.adamjamesnaylor.com/2013/01/23/Setting-Readonly-Fields-From-Chained-Constructors.aspx


4
Alanlar hala yapıcıda görevlendirilmiştir .. "dolaşmak" diye bir şey yoktur. Değerlerin tek ifadelerden, ayrıştırılmış bir karmaşık tipten olması veya referans semantik tarafından çağrı yoluyla atanması önemli değildir out.
user2864740 12:07

Bu, soruyu cevaplamaya bile çalışmaz.
Sheridan

2

Şaşırtıcı bir şekilde, Jon Skeet'in Noda Time kütüphanesini test ederken bulduğu gibi salt okunur kod aslında daha yavaş bir kodla sonuçlanabilir. Bu durumda, 20 saniyede yapılan bir test, salt okunur kaldırıldıktan sadece 4 saniye sürdü.

https://codeblog.jonskeet.uk/2014/07/16/micro-optimization-the-surprising-inefficiency-of-readonly-fields/


3
Alan readonly structC # 7.2'de bir türdeyse, alanı salt okunur yapma avantajının ortadan kalktığını unutmayın.
Jon Skeet

1

Program boyunca aynı kalması gereken önceden tanımlanmış veya önceden hesaplanmış bir değeriniz varsa, sabit kullanmalısınız, ancak çalışma zamanında sağlanması gereken bir değer varsa ancak atandıktan sonra program boyunca aynı kalmalıdır. Sadece oku. örneğin, program başlangıç ​​zamanını atamanız gerekiyorsa veya nesne başlatma sırasında kullanıcı tarafından sağlanan bir değeri saklamanız gerekiyorsa ve bunu başka değişikliklerle sınırlamanız gerekiyorsa, salt okunur kullanmanız gerekir.


1

Bu soruyu cevaplamak için temel bir yön eklemek:

Özellikler, setoperatörden ayrılarak salt okunur olarak ifade edilebilir . Bu nedenle, çoğu durumda readonlyanahtar kelimeyi mülklere eklemenize gerek yoktur :

public int Foo { get; }  // a readonly property

Bunun aksine: Alanlar readonlybenzer bir etki elde etmek için anahtar kelimeye ihtiyaç duyar :

public readonly int Foo; // a readonly field

Bu nedenle, bir alanı , herhangi bir nedenle istenirse, alanı bir mülke değiştirmek zorunda kalmadan, operatörsüz readonlybir özellik olarak benzer bir yazma koruma seviyesine ulaşmak olabileceğinin işaretlenmesinin bir yararı set.


2 arasında davranış farkı var mı?
petrosmm

0

Özel salt okunur dizilere dikkat edin. Bunlar bir istemci nesne olarak maruz kalırsanız (bunu benim gibi COM birlikte çalışma için yapabilirsiniz) istemci dizi değerlerini işleyebilir. Bir diziyi nesne olarak döndürürken Clone () yöntemini kullanın.


20
Hayır; ReadOnlyCollection<T>dizi yerine gösterme .
SLaks

Bu soruya cevap vermediği için bir cevap değil, bir yorum olmalıdır ...
Peter

Funnily, geçen hafta başka bir yazıya yaptığımda yorum yapmak yerine bu tür bir şeyi bir cevap olarak koymam söylendi.
Kyle Baran

2013 itibariyle, ImmutableArray<T>bir arabirime ( IReadOnlyList<T>) veya bir sınıfa ( ReadOnlyCollection) sarmaktan kaçınarak kullanabilirsiniz . Yerel dizilerle karşılaştırılabilir performansa sahiptir: blogs.msdn.microsoft.com/dotnet/2013/06/24/…
Charles Taylor

0

Pahalı Bağımlılık Özelliklerine olan ihtiyacı ortadan kaldırdığı için WPF'de bir performans avantajı olabilir. Bu özellikle koleksiyonlarda faydalı olabilir


0

Salt okunur işaretlemenin kullanımının bir başka ilginç kısmı, alanı singletondaki başlatmadan korumak olabilir.

örneğin csharpindepth kodunda :

public sealed class Singleton
{
    private static readonly Lazy<Singleton> lazy =
        new Lazy<Singleton>(() => new Singleton());

    public static Singleton Instance { get { return lazy.Value; } }

    private Singleton()
    {
    }
}

readonly, Singleton alanını iki kez başlatılmasını önlemede küçük bir rol oynar. Başka bir ayrıntı da, söz konusu senaryo için const'ı kullanamayacağınızdır, çünkü const derleme zamanında yaratmayı zorlar, ancak singleton çalışma zamanında yaratma yapar.


0

readonlybeyanda başlatılabilir veya değerini yalnızca kurucudan alabilir. Bunun aksine constaynı anda başlatılmalı ve beyan edilmelidir. readonly her şeye const sahip, ayrıca kurucu başlatma

kod https://repl.it/HvRU/1

using System;

class MainClass {
    public static void Main (string[] args) {

        Console.WriteLine(new Test().c);
        Console.WriteLine(new Test("Constructor").c);
        Console.WriteLine(new Test().ChangeC()); //Error A readonly field 
        // `MainClass.Test.c' cannot be assigned to (except in a constructor or a 
        // variable initializer)
    }


    public class Test {
        public readonly string c = "Hello World";
        public Test() {

        }

        public Test(string val) {
          c = val;
        }

        public string ChangeC() {
            c = "Method";
            return c ;
        }
    }
}
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.