สิ่งห่อหุ้มควรเปรียบเทียบให้เท่ากันโดยใช้ตัวดำเนินการ == เมื่อทำการล้อมวัตถุเดียวกันหรือไม่?


19

ฉันกำลังเขียน wrapper สำหรับองค์ประกอบ XML ที่ช่วยให้นักพัฒนาสามารถวิเคราะห์แอตทริบิวต์จาก XML ได้อย่างง่ายดาย เสื้อคลุมไม่มีสถานะอื่นนอกจากวัตถุที่ถูกห่อ

ฉันกำลังพิจารณาการติดตั้งต่อไปนี้ (ทำให้ง่ายขึ้นสำหรับตัวอย่างนี้) ซึ่งรวมถึงโอเวอร์โหลดสำหรับ==โอเปอเรเตอร์

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);
    }
}

ตามที่ฉันเข้าใจสำนวน c # ==ผู้ปฏิบัติงานมีไว้สำหรับความเท่าเทียมในการอ้างอิงในขณะที่Equals()วิธีการสำหรับความเท่าเทียมกันของค่า แต่ในกรณีนี้ "ค่า" เป็นเพียงการอ้างอิงถึงวัตถุที่ถูกห่อ ดังนั้นฉันจึงไม่ชัดเจนว่าสิ่งที่เป็นธรรมดาหรือสำนวนสำหรับ c #

ตัวอย่างเช่นในรหัสนี้ ...

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 และ b เหมือนกัน"? หรือว่าจะแปลกคือละเมิดหลักความประหลาดใจอย่างน้อย ?


ทุกครั้งที่ผมลบล้างEqualsฉันไม่เคยลบล้าง==( แต่ไม่เคยวิธีอื่น ๆ ) ขี้เกียจเป็นสำนวนหรือเปล่า หากฉันได้รับพฤติกรรมที่แตกต่างโดยไม่มีนักแสดงที่ชัดเจนว่าละเมิดความประหลาดใจน้อยที่สุด
Radarbob

คำตอบสำหรับสิ่งนี้ขึ้นอยู่กับสิ่งที่ NameAttribute ทำ - แก้ไของค์ประกอบพื้นฐาน? เป็นข้อมูลเพิ่มเติมหรือไม่ ความหมายของรหัสตัวอย่าง (และควรพิจารณาว่าเท่ากันหรือไม่) การเปลี่ยนแปลงขึ้นอยู่กับว่าดังนั้นฉันคิดว่าคุณจำเป็นต้องกรอกรหัสข้อผิดพลาด
ข้อผิดพลาด

@Errorsatz ฉันขอโทษ แต่ฉันต้องการให้ตัวอย่างกระชับและฉันคิดว่ามันชัดเจนว่ามันจะแก้ไของค์ประกอบห่อ (โดยเฉพาะการปรับเปลี่ยนแอตทริบิวต์ XML ชื่อ "ชื่อ.") แต่เฉพาะเรื่องแทบ - ประเด็นคือ wrapper นั้นอนุญาตให้อ่าน / เขียนการเข้าถึงองค์ประกอบที่ถูกห่อ แต่ไม่มีสถานะของมันเอง
John Wu

4
ในกรณีนี้พวกเขาสำคัญ - หมายความว่าการมอบหมาย "Hello" และ "World" นั้นทำให้เข้าใจผิดเพราะหลังจะเขียนทับอดีต ซึ่งหมายความว่าฉันเห็นด้วยกับคำตอบของมาร์ตินว่าทั้งสองจะได้รับการพิจารณาอย่างเท่าเทียมกัน หาก NameAttribute แตกต่างกันระหว่างพวกเขาจริง ๆ ฉันจะไม่ถือว่าพวกเขาเท่าเทียมกัน
ข้อผิดพลาด

2
"ตามที่ฉันเข้าใจสำนวน c # ตัวดำเนินการ == สำหรับความเท่าเทียมในการอ้างอิงในขณะที่วิธี Equals () สำหรับความเท่าเทียมกันตามตัวอักษร" มันเป็นอย่างไร เวลาส่วนใหญ่ที่ฉันเคยเห็น == มากไปนั้นมีไว้เพื่อความเท่าเทียมกันของค่า ตัวอย่างที่สำคัญที่สุดคือ System.String
Arturo Torres Sánchez

คำตอบ:


17

เนื่องจากการอ้างอิงถึงสิ่งห่อหุ้มXElementไม่สามารถเปลี่ยนแปลงได้จึงไม่มีความแตกต่างที่สังเกตได้จากภายนอกทั้งสองกรณีของXmlWrapperองค์ประกอบเดียวกันดังนั้นจึงเหมาะสมที่==จะสะท้อนความจริงนี้

รหัสลูกค้ามักจะใส่ใจเกี่ยวกับความเสมอภาคเชิงตรรกะ (ซึ่งโดยค่าเริ่มต้นจะมีการใช้งานโดยใช้ความเท่าเทียมกันอ้างอิงสำหรับประเภทการอ้างอิง) ความจริงที่ว่ามีสองอินสแตนซ์บนฮีปคือรายละเอียดการใช้งานที่ลูกค้าไม่ควรสนใจ (และผู้ที่จะใช้Object.ReferenceEqualsโดยตรง)


9

ถ้าคุณคิดว่ามันสมเหตุสมผลที่สุด

คำถามและคำตอบนั้นเป็นเรื่องของความคาดหวังของนักพัฒนาซึ่งไม่ใช่ข้อกำหนดทางเทคนิค

หากคุณคิดว่า wrapper ไม่มีตัวตนและมีการกำหนดโดยหมดจดจากเนื้อหาของมันแล้วคำตอบสำหรับคำถามของคุณคือใช่

แต่นี่เป็นปัญหาที่เกิดซ้ำ ควรห่อสองรายการแสดงความเท่าเทียมกันเมื่อพวกเขาห่อวัตถุที่แตกต่างกัน แต่มีวัตถุทั้งสองที่มีเนื้อหาเดียวกันแน่นอน?

คำตอบซ้ำตัวเอง หากวัตถุเนื้อหาไม่มีตัวตนส่วนบุคคลและแทนที่จะถูกกำหนดโดยเนื้อหาของพวกเขาอย่างสิ้นเชิงแล้ววัตถุเนื้อหานั้นจะถูกห่อหุ้มอย่างมีประสิทธิภาพซึ่งจะแสดงความเท่าเทียมกัน ถ้าคุณหุ้มวัตถุเนื้อหาใน wrapper อื่นแล้ว wrapper (เพิ่มเติม) นั้นก็ควรมีความเท่าเทียมกัน

มันturtles ตลอดทางลง


เคล็ดลับทั่วไป

เมื่อใดก็ตามที่คุณเบี่ยงเบนจากพฤติกรรมเริ่มต้นควรมีการบันทึกไว้อย่างชัดเจน ในฐานะนักพัฒนาฉันคาดหวังว่าการอ้างอิงสองประเภทจะไม่แสดงความเท่าเทียมกันแม้ว่าเนื้อหานั้นจะเท่ากัน หากคุณเปลี่ยนพฤติกรรมนั้นฉันขอแนะนำให้คุณบันทึกไว้อย่างชัดเจนเพื่อให้นักพัฒนาซอฟต์แวร์ทุกคนทราบถึงพฤติกรรมผิดปกตินี้


ตามที่ฉันเข้าใจสำนวน c # ==ผู้ปฏิบัติงานมีไว้สำหรับความเท่าเทียมในการอ้างอิงในขณะที่Equals()วิธีการสำหรับความเท่าเทียมกันของค่า

นั่นคือพฤติกรรมเริ่มต้น แต่นี่ไม่ใช่กฎที่เคลื่อนที่ไม่ได้ มันเป็นเรื่องของการประชุม แต่การประชุมสามารถเปลี่ยนแปลงที่สมเหตุสมผล

stringเป็นตัวอย่างที่ดีที่นี่เช่นเดียวกับ==การตรวจสอบความเท่าเทียมกันของค่า (แม้ว่าจะไม่มีการฝึกงานสตริง!) ทำไม? พูดง่ายๆ: เนื่องจากการมีสตริงทำตัวเหมือนวัตถุที่ให้คุณค่าจึงทำให้นักพัฒนาส่วนใหญ่ใช้งานง่ายขึ้น

ถ้า codebase ของคุณ (หรือชีวิตของนักพัฒนาของคุณ) ได้ง่ายสะดุดตาโดยมีห่อของคุณแสดงความเสมอภาคค่าผ่านคณะกรรมการไปได้ ( แต่เอกสารมัน )

หากคุณไม่ต้องการการตรวจสอบความเท่าเทียมกันของข้อมูลอ้างอิง (หรือโดเมนธุรกิจของคุณแสดงผลไม่ได้) ก็ไม่มีประโยชน์ที่จะตรวจสอบความเท่าเทียมกันของข้อมูลอ้างอิง จะดีกว่าที่แล้วแทนที่ด้วยการตรวจสอบความเสมอภาคค่าเพื่อป้องกันไม่ให้เกิดข้อผิดพลาดของนักพัฒนา
อย่างไรก็ตามจงตระหนักว่าหากคุณต้องการการตรวจสอบความเท่าเทียมกันของข้อมูลอ้างอิงภายหลังจากนั้นจึงทำการปรับปรุงใหม่ซึ่งอาจต้องใช้ความพยายามอย่างมาก


ฉันอยากรู้ว่าทำไมคุณคาดหวังว่าประเภทการอ้างอิงจะไม่นิยามความเท่าเทียมกันของเนื้อหา ประเภทส่วนใหญ่ไม่ได้กำหนดความเท่าเทียมกันเพียงเพราะมันไม่จำเป็นสำหรับโดเมนของพวกเขาไม่ใช่เพราะพวกเขาต้องการความเท่าเทียมกันอ้างอิง
คาซาบลังก้า

3
@ คาซาบลังก้า: ฉันคิดว่าคุณตีความคำจำกัดความที่แตกต่างของ "คาด" (เช่นความต้องการกับสมมติฐาน) หากไม่มีเอกสารฉันคาดหวัง (เช่นสมมติว่า) ==ตรวจสอบความเท่าเทียมกันของการอ้างอิงเนื่องจากนี่เป็นพฤติกรรมเริ่มต้น อย่างไรก็ตามหาก==จริง ๆ แล้วตรวจสอบความเท่าเทียมกันของค่าฉันคาดหวังว่า (เช่นต้องการ) ว่าเอกสารนี้ถูกบันทึกไว้อย่างชัดเจน I'm curious why you expect that reference types won't define content equality.พวกเขาไม่ได้กำหนดไว้โดยค่าเริ่มต้นแต่นั่นไม่ได้หมายความว่าไม่สามารถทำได้ ฉันไม่เคยบอกว่าไม่สามารถทำได้ (หรือไม่ควรทำ) ฉันไม่คาดหวัง (เช่นสมมติ) เป็นค่าเริ่มต้น
Flater

ฉันเห็นสิ่งที่คุณหมายถึงขอบคุณสำหรับการชี้แจง
คาซาบลังก้า

2

คุณกำลังเปรียบเทียบสตริงโดยทั่วไปดังนั้นฉันจะประหลาดใจถ้าสอง wrappers ที่มีเนื้อหา XML เดียวกันนั้นไม่ถือว่าเท่ากันไม่ว่าจะตรวจสอบโดยใช้ Equals หรือ ==

กฎของสำนวนอาจเหมาะสมสำหรับวัตถุประเภทอ้างอิงโดยทั่วไป แต่สตริงนั้นมีความพิเศษในแง่ของสำนวนคุณควรปฏิบัติต่อพวกเขาและถือว่าพวกมันเป็นค่าแม้ว่าในทางเทคนิคแล้วมันเป็นประเภทอ้างอิง

Wrapper Postfix ของคุณเพิ่มความสับสน โดยพื้นฐานแล้วจะพูดว่า "ไม่ใช่องค์ประกอบ XML" ดังนั้นฉันควรปฏิบัติต่อมันเป็นประเภทอ้างอิงหลังจากทั้งหมดหรือไม่ ความหมายนี้จะไม่สมเหตุสมผล ฉันจะสับสนน้อยลงถ้าคลาสมีชื่อว่า XmlContent สิ่งนี้จะส่งสัญญาณว่าเราใส่ใจเนื้อหาไม่ใช่รายละเอียดการใช้งานด้านเทคนิค


คุณจะใส่ขีด จำกัด ระหว่าง "วัตถุที่สร้างจากสตริง" และ "โดยทั่วไปคือสตริง" ดูเหมือนว่าคำจำกัดความที่ค่อนข้างคลุมเครือจากมุมมอง API ภายนอก ผู้ใช้ API ต้องเดา internals เพื่อคาดเดาพฤติกรรมหรือไม่
Arthur Havlicek

@ ความหมายของคลาส / วัตถุควรมีเงื่อนงำ และบางครั้งมันก็ไม่ใช่สิ่งที่ชัดเจนดังนั้นคำถามนี้ สำหรับประเภทมูลค่าจริงทุกคนจะชัดเจน สำหรับสตริงจริงด้วย ประเภทควรบอกในที่สุดว่าการเปรียบเทียบควรเกี่ยวข้องกับเนื้อหาหรือเอกลักษณ์ของวัตถุ
Martin Maat
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.