Herkese açık değiştirilebilir alanları veya özellikleri olan yapılar kötü değildir.
"This" i mutasyona uğratan yapısal yöntemler (özellik ayarlayıcılarından farklı olarak) biraz kötülüktür, çünkü .net bunları yapmayan yöntemlerden ayırmanın bir yolunu sağlamaz. "Bu" ifadesini değiştirmeyen yapı yöntemleri, savunma amaçlı kopyalamaya gerek kalmadan salt okunur yapılarda bile çalıştırılabilir olmalıdır. "Bunu" değiştiren yöntemler salt okunur yapılarda hiç çalıştırılmamalıdır. .Net, "bu" değerini değiştirmeyen yapı yöntemlerinin salt okunur yapılarda çağrılmasını engellemek istemediğinden, salt okunur yapıların değiştirilmesine izin vermek istemediğinden, yapıları defalarca sadece bağlamlar, tartışmalı olarak her iki dünyanın da kötüleşmesi.
Bununla birlikte, salt okunur bağlamlarda kendi kendini değiştiren yöntemlerin ele alınmasına ilişkin sorunlara rağmen, değiştirilebilir yapılar genellikle değiştirilebilir sınıf türlerinden çok daha üstün bir anlambilim sunar. Aşağıdaki üç yöntem imzasını göz önünde bulundurun:
struct PointyStruct {genel int x, y, z;};
sınıf PointyClass {public int x, y, z;};
void Yöntem1 (PointyStruct foo);
geçersiz Yöntem2 (ref PointyStruct foo);
void Yöntem3 (PointyClass foo);
Her yöntem için aşağıdaki soruları cevaplayın:
- Yöntemin "güvensiz" kod kullanmadığını varsayarsak, foo değiştirebilir mi?
- Yöntem çağrılmadan önce 'foo' dış referansları yoksa, daha sonra dış referans var mı?
Yanıtlar:
Soru 1::
Method1()
hayır (açık niyet)
Method2()
: evet (açık niyet)
Method3()
: evet (belirsiz niyet)
Soru 2
Method1()
:: hayır
Method2()
: hayır (güvenli değilse)
Method3()
: evet
Yöntem1 foo değiştiremez ve hiçbir zaman başvuru alır. Yöntem2, foo alanlarına kısa ömürlü bir başvuru alır, bu da foo alanlarını herhangi bir sırayla, geri dönene kadar değiştirmek için kullanabilir, ancak bu başvuruyu devam ettiremez. Yöntem2 dönmeden önce, güvenli olmayan kod kullanmadıkça, 'foo' başvurusundan yapılmış olabilecek tüm kopyalar kaybolacaktır. Yöntem3, Yöntem2'den farklı olarak, foo'ya karışık olarak paylaşılabilir bir başvuru alır ve bununla ne yapabileceğini söylemez. Foo'yu hiç değiştirmeyebilir, foo'yu değiştirebilir ve sonra geri dönebilir veya başka bir iş parçacığına foo'ya, gelecekteki keyfi bir zamanda onu rastgele bir şekilde değiştirebilecek bir referans verebilir.
Yapı dizileri harika anlambilim sunar. Rectangle türündeki RectArray [500] verildiğinde, örneğin 123 öğesini eleman 456'ya nasıl kopyalayacağınız açıktır ve daha sonra bir süre sonra eleman 456'yı 556'yı rahatsız etmeden elemanın genişliğini nasıl ayarlayacağınız açıktır. "RectArray [432] = RectArray [321 ]; ...; RectArray [123]. Genişlik = 555; ". Dikdörtgenin Width adında bir tamsayı alanına sahip bir yapı olduğunu bilmek, yukarıdaki ifadeler hakkında herkesin bilmesi gereken birini söyler.
Şimdi RectClass'ın Rectangle ile aynı alanlara sahip bir sınıf olduğunu ve bir RectClass tipi RectClassArray [500] üzerinde aynı işlemleri yapmak istediğini varsayalım. Belki de dizinin değiştirilebilir RectClass nesnelerine önceden başlatılmış 500 değişmez referansı tutması beklenir. bu durumda, uygun kod "RectClassArray [321] .SetBounds (RectClassArray [456]); ...; RectClassArray [321] .X = 555;" gibi bir şey olacaktır. Belki de dizinin değişmeyecek örnekleri içerdiği varsayılır, bu nedenle uygun kod daha çok "RectClassArray [321] = RectClassArray [456]; ...; RectClassArray [321] = Yeni RectClass (RectClassArray [321) ]); RectClassArray [321] .X = 555; " Birinin ne yapması gerektiğini bilmek için, RectClass hakkında çok daha fazla şey bilmek gerekir (örneğin bir kopya oluşturucu, bir kopyadan çıkarma yöntemi vb. ) ve dizinin kullanım amacı. Hiçbir yerde bir yapı kullanmak kadar temiz değil.
Emin olmak için, ne yazık ki, bir dizi dışında herhangi bir kap sınıfı için bir yapı dizisinin temiz semantiğini sunmanın güzel bir yolu yoktur. Bir koleksiyon örneğin bir dizeyle dizine eklenmesini isterse, muhtemelen en iyisi, dizin için bir dize, genel bir parametre ve geçirilecek bir temsilci kabul edecek genel bir "ActOnItem" yöntemi sunmak olacaktır. hem genel parametreye hem de koleksiyon öğesine referans vererek. Bu, yapı dizileriyle neredeyse aynı semantiğe izin verir, ancak vb.net ve C # insanları güzel bir sözdizimi sunmak için takip edilemezse, kod makul performans olsa bile tıknaz görünümlü olacaktır (genel bir parametre geçirir) statik delege kullanılmasına izin verir ve geçici sınıf örnekleri oluşturma gereksinimini önler).
Şahsen ben nefret duydum Eric Lippert ve ark. değişebilir değer türleri ile ilgili azarlama. Her yerde kullanılan karışık referans türlerinden çok daha temiz semantikler sunuyorlar. .Net'in değer türleri desteğiyle ilgili bazı kısıtlamalara rağmen, değişebilir değer türlerinin diğer herhangi bir türden daha uygun olduğu birçok durum vardır.
int
s,bool
s iddia etmek gibidir ve diğer tüm değer türleri kötülüktür. Değişebilirlik ve değişmezlik vakaları vardır. Bu durumlar, bellek ayırma / paylaşma türüne değil, verilerin oynadığı role bağlıdır.