Aynı nesneyi sararken sarmalayıcılar == operatörünü kullanarak eşit karşılaştırmalı mıdır?


19

Bir geliştiricinin XML'den öznitelikleri kolayca ayrıştırmasını sağlayan XML öğeleri için bir sarıcı yazıyorum. Sarıcı, sarılmakta olan nesneden başka bir duruma sahip değil.

Ben ==operatör için bir aşırı yük içeren aşağıdaki uygulamayı (bu örnek için basitleştirilmiş) düşünüyorum .

class XmlWrapper
{
    protected readonly XElement _element;

    public XmlWrapper(XElement element)
    {
        _element = element;
    }

    public string NameAttribute
    {
        get
        {
            //Get the value of the name attribute
        }
        set
        {
            //Set the value of the name attribute
        }
    }

    public override bool Equals(object other)
    {
        var o = other as XmlWrapper;
        if (o == null) return false;
        return _element.Equals(o._element);
    }

    public override int GetHashCode()
    {
        return _element.GetHashCode();
    }

    static public bool operator == (XmlWrapper lhs, XmlWrapper rhs)
    {
        if (ReferenceEquals(lhs, null) && ReferenceEquals(rhs, null)) return true;
        if (ReferenceEquals(lhs, null) || ReferenceEquals(rhs, null)) return false;

        return lhs._element == rhs._element;
    }

    static public bool operator != (XmlWrapper lhs, XmlWrapper rhs)
    {
        return !(lhs == rhs);
    }
}

İdiyomatik c # anladığım gibi ==, Equals()yöntem değer eşitliği için operatör referans eşitliği içindir. Ancak bu durumda, "değer" yalnızca kaydırılmakta olan nesneye bir referanstır. Bu yüzden ne geleneksel veya deyim c # için net değilim.

Örneğin, bu kodda ...

var underlyingElement = new XElement("Foo");
var a = new XmlWrapper(underlyingElement);
var b = new XmlWrapper(underlyingElement);

a.NameAttribute = "Hello";
b.NameAttribute = "World";

if (a == b)
{
    Console.WriteLine("The wrappers a and b are the same.");
}

.... "a ve b sarmalayıcıları aynı mı?" Yoksa bu garip, yani en az şaşkınlık ilkesini ihlal eder mi?


Her Equalszaman aşırıya kaçtığım için asla aşırıya kaçmam ==(ama asla tersi ). Tembel deyimsel mi? En az şaşkınlığı ihlal eden açık bir oyuncu olmadan farklı davranışlar alırsam.
radarbob

Bunun cevabı NameAttribute'un temel öğeyi değiştirdiğine bağlıdır. Ek bir veri parçası mı? Örnek kodun anlamı (ve eşit kabul edilmesi gerekip gerekmediği) buna bağlı olarak değişir, bu yüzden doldurmanız gerektiğini düşünüyorum.
Errorsatz

@Errorsatz Özür dilerim, ancak örneği kısa ve öz tutmak istedim ve kaydırılan öğeyi değiştireceğinin açık olduğunu varsaydım (özellikle "name" adlı XML özniteliğini değiştirerek). sargının, sarılmış öğeye okuma / yazma erişimine izin verdiğini, ancak kendi durumunu içermediğini unutmayın.
John Wu

4
Eh, bu durumda önemli - bu "Merhaba" ve "Dünya" ödevi yanıltıcı olduğu anlamına gelir, çünkü ikincisi öncekinin üzerine yazacaktır. Bu, Martin'in bu ikisinin eşit kabul edilebileceği cevabına katılıyorum demektir. NameAttribute aslında aralarında farklı olsaydı, onları eşit saymazdım.
Errorsatz

2
"Deyimsel c # anladığım gibi, == işleci referans eşitliği için iken, Equals () yöntemi değer eşitliği içindir." Öyle mi? == Aşırı yük gördüğüm çoğu zaman değer eşitliği içindir. Bunun en önemli örneği System.String.
Arturo Torres Sánchez

Yanıtlar:


17

Sarılı referansın XElementdeğişmez olması XmlWrappernedeniyle, aynı öğeyi saran iki örneği arasında harici olarak gözlemlenebilir bir fark yoktur , bu nedenle ==bu gerçeği yansıtmak için aşırı yüklenmenin anlamı vardır .

İstemci kodu neredeyse her zaman mantıksal eşitliğe önem verir (varsayılan olarak referans türleri için referans eşitliği kullanılarak uygulanır). Öbek üzerinde iki örnek olması, istemcilerin umursamaması gereken bir uygulama detayıdır (ve Object.ReferenceEqualsdoğrudan kullananlar ).


9

En mantıklı olduğunu düşünüyorsanız

Soru ve cevap geliştirici beklentisi meselesidir , bu teknik bir gereklilik değildir.

EĞER Eğer bir kimliğe sahip ve onun içerikleriyle tamamen tanımlanabilir değil bir sarmalayıcı düşünün, sonra sorunun cevabı evet.

Ancak bu tekrar eden bir sorundur. İki sargı, farklı nesneleri sararken, ancak her iki nesne de aynı içeriğe sahipken eşitlik göstermeli mi?

Cevap kendini tekrarlıyor. EĞER içerik nesneleri hiçbir kişisel kimliğe sahip ve bunun yerine tamamen içeriklerine göre tanımlanır ise içeriklerin nesneleri etkin bir eşitlik sergileyecek sarıcıları. Daha sonra içerik nesnelerini başka bir paketleyiciye sararsanız, bu (ek) paketleyicinin de eşitlik göstermesi gerekir.

Tamamen kaplumbağalar .


Genel ipucu

Varsayılan davranıştan saptığınızda, açıkça belirtilmelidir. Bir geliştirici olarak, iki referans türünün içeriği eşit olsa bile eşitlik göstermeyeceğini umuyorum. Bu davranışı değiştirirseniz, tüm geliştiricilerin bu atipik davranışın farkında olması için açıkça belgelemenizi öneririm.


İdiyomatik c # anladığım gibi ==, Equals()yöntem değer eşitliği için operatör referans eşitliği içindir.

Bu onun varsayılan davranışıdır, ancak bu taşınmaz bir kural değildir. Bu bir konvansiyon meselesidir, ancak konvansiyonlar haklı olduğu yerde değiştirilebilir .

stringburada ==da bir değer eşitliği denetimi (dize stajyerliği olmasa bile!) harika bir örnektir . Neden? Basitçe söylemek gerekirse: dizelerin değer nesneleri gibi davranması çoğu geliştiriciye daha sezgisel geliyor.

Kod tabanınız (veya geliştiricilerinizin yaşamları), paketleyicilerinizin yönetim kurulu genelinde değer eşitliği göstermesini sağlayarak önemli ölçüde basitleştirilebiliyorsa, buna gidin (ancak belgeleyin ).

Asla referans eşitlik kontrollerine ihtiyacınız yoksa (veya işletme alanınız tarafından işe yaramazsa), referans eşitliği kontrolünü korumanın bir anlamı yoktur. Daha sonra geliştirici hatasını önlemek için bir değer eşitliği denetimi ile değiştirmek daha iyidir .
Bununla birlikte, daha sonra çizginin aşağısında referans eşitlik kontrollerine ihtiyaç duymanız gerektiğinin farkında olun, yeniden uygulamak kayda değer bir çaba gerektirebilir.


Referans türlerinin içerik eşitliğini tanımlamamasını neden beklediğinizi merak ediyorum. Çoğu tür eşitliği tanımlamaz, çünkü bu alan adları için önemli değildir, referans eşitliği istedikleri için değil .
casablanca

3
@casablanca: Sanırım farklı bir "beklenti" tanımını yorumluyorsunuz (yani varsayım yerine gereksinim). Belgeler olmadan ==, bu varsayılan davranış olduğu için referans eşitliğini kontrol eder (yani varsayalım) . Ancak, ==aslında değer eşitliğini denetler, bunun açıkça belgelendiğini (yani gerektirir) bekliyoruz. Varsayılan olarakI'm curious why you expect that reference types won't define content equality. tanımlamazlar , ancak bu yapılamayacağı anlamına gelmez. Ben asla yapamayacağını (ya da yapılmaması gerektiğini) söylemedim, sadece varsayılan olarak beklemiyorum (yani varsayalım).
Eylül'de

Ne demek istediğini anlıyorum, açıkladığın için teşekkürler.
casablanca

2

Temelde dizeleri karşılaştırıyorsunuz, bu yüzden aynı XML içeriğini içeren iki paket eşit olarak kabul edilmezse Şaşırırdım, Eşittir veya == kullanılarak kontrol edilir.

Deyimsel kural, genel olarak referans tipi nesneler için anlamlı olabilir, ancak dizeler deyimsel anlamda özeldir, teknik olarak referans türleri olmalarına rağmen bunları değer olarak kabul etmeniz gerekir.

Wrapper postfix'iniz yine de karışıklık yaratıyor. Temel olarak "XML öğesi değil" der. Sonuçta referans türü olarak mı davranmalıyım? Anlamsal olarak bu bir anlam ifade etmeyecektir. Sınıf XmlContent adlı olsaydı daha az kafam karışırdı. Bu, teknik uygulama ayrıntılarını değil içeriği önemsediğimizi gösterecektir.


"Bir dizeden oluşturulan bir nesne" ile "temel olarak bir dize" arasındaki sınırı nereye koyardınız? Dış API perspektifinden oldukça belirsiz bir tanım gibi görünüyor. API kullanıcısı aslında davranışı tahmin etmek için dahili bilgileri tahmin etmek zorunda mı?
Arthur Havlicek

@Arthur Sınıf / nesnenin anlambilimi ipucunu sağlamalıdır. Ve bazen o kadar açık değil, bu yüzden bu soru. Gerçek değer türleri için herkes tarafından görülecektir. Gerçek dizgiler için de. Tür eninde sonunda bir karşılaştırmanın içerik veya nesne kimliği içerip içermemesi gerektiğini söylemelidir.
Martin Maat
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.