ไม่สามารถใช้โอเปอเรเตอร์ == กับประเภททั่วไปใน C # ได้หรือไม่


326

ตามเอกสารของ==ผู้ประกอบการในMSDN ,

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

เหตุใดข้อมูลโค้ดนี้จึงไม่สามารถรวบรวมได้

bool Compare<T>(T x, T y) { return x == y; }

ฉันได้รับข้อผิดพลาดผู้ประกอบการ '==' ไม่สามารถนำไปใช้กับตัวถูกดำเนินการชนิด 'T' และ 'T' ฉันสงสัยว่าเพราะเท่าที่ฉันเข้าใจตัว==ดำเนินการที่กำหนดไว้ล่วงหน้าสำหรับทุกประเภท?

แก้ไข:ขอบคุณทุกคน ตอนแรกฉันไม่ได้สังเกตว่าคำสั่งนั้นเกี่ยวกับประเภทการอ้างอิงเท่านั้น ฉันยังคิดว่าการเปรียบเทียบแบบทีละบิตมีไว้สำหรับค่าทุกประเภทซึ่งตอนนี้ฉันรู้ว่าไม่ถูกต้อง

แต่ในกรณีที่ฉันใช้ประเภทอ้างอิงตัว==ดำเนินการจะใช้การเปรียบเทียบการอ้างอิงที่กำหนดไว้ล่วงหน้าหรือจะใช้ตัวดำเนินการรุ่นที่มีการโอเวอร์โหลดของผู้ประกอบการหรือไม่

แก้ไข 2:จากการทดลองและข้อผิดพลาดเราเรียนรู้ว่า==ผู้ประกอบการจะใช้การเปรียบเทียบการอ้างอิงที่กำหนดไว้ล่วงหน้าเมื่อใช้ประเภททั่วไปที่ไม่ จำกัด ที่จริงแล้วคอมไพเลอร์จะใช้วิธีการที่ดีที่สุดที่จะหาอาร์กิวเมนต์ประเภทที่ จำกัด แต่จะไม่ดูเพิ่มเติม ตัวอย่างเช่นรหัสด้านล่างจะพิมพ์ทุกtrueครั้งแม้ว่าTest.test<B>(new B(), new B())จะถูกเรียกว่า:

class A { public static bool operator==(A x, A y) { return true; } }
class B : A { public static bool operator==(B x, B y) { return false; } }
class Test { void test<T>(T a, T b) where T : A { Console.WriteLine(a == b); } }

ดูคำตอบของฉันอีกครั้งสำหรับคำตอบสำหรับคำถามติดตามของคุณ
Giovanni Galbo

มันอาจจะมีประโยชน์ที่จะเข้าใจว่าแม้ไม่มี generics มีบางประเภทที่==ไม่ได้รับอนุญาตระหว่างสองตัวถูกดำเนินการประเภทเดียวกัน สิ่งนี้เป็นจริงสำหรับstructประเภท (ยกเว้นประเภท "ที่กำหนดไว้ล่วงหน้า") ซึ่งไม่ได้โหลดเกินoperator ==จำนวน เป็นตัวอย่างง่ายๆลองนี้:var map = typeof(string).GetInterfaceMap(typeof(ICloneable)); Console.WriteLine(map == map); /* compile-time error */
Jeppe Stig Nielsen

ต่อความคิดเห็นเก่าของฉันเอง ยกตัวอย่างเช่น (ดูหัวข้ออื่น ๆ ) ด้วยvar kvp1 = new KeyValuePair<int, int>(); var kvp2 = kvp1;แล้วคุณจะไม่สามารถตรวจสอบkvp1 == kvp2เพราะKeyValuePair<,>เป็น struct ก็ไม่ได้เป็น C # operator ==ประเภทที่กำหนดไว้ล่วงหน้าและไม่เกิน ตัวอย่างvar li = new List<int>(); var e1 = li.GetEnumerator(); var e2 = e1;ที่คุณไม่สามารถทำได้e1 == e2(ที่นี่เรามีโครงสร้างซ้อนกันList<>.Enumerator(เรียก"List`1+Enumerator[T]"โดยรันไทม์) ซึ่งไม่ได้โหลดเกิน==)
Jeppe Stig Nielsen

RE: "เหตุใดข้อมูลโค้ดนี้จึงไม่สามารถรวบรวมได้" - เอ่อ ... เพราะคุณไม่สามารถกลับมาboolจากvoid...
BrainSlugs83

1
@ BrainSlugs83 ขอบคุณที่ติดตามบั๊กอายุ 10 ปี!
Hosam Aly

คำตอบ:


143

"... โดยค่าเริ่มต้น == จะทำงานตามที่อธิบายไว้ข้างต้นสำหรับทั้งประเภทการอ้างอิงที่กำหนดไว้ล่วงหน้าและที่ผู้ใช้กำหนด"

ประเภท T ไม่จำเป็นต้องเป็นประเภทอ้างอิงดังนั้นคอมไพเลอร์จึงไม่สามารถทำการสันนิษฐานได้

อย่างไรก็ตามสิ่งนี้จะรวบรวมเพราะชัดเจนมากขึ้น:

    bool Compare<T>(T x, T y) where T : class
    {
        return x == y;
    }

ติดตามคำถามเพิ่มเติมได้ว่า "แต่ในกรณีที่ฉันใช้ประเภทอ้างอิงตัวดำเนินการ == จะใช้การเปรียบเทียบการอ้างอิงที่กำหนดไว้ล่วงหน้าหรือจะใช้ตัวดำเนินการเวอร์ชันโอเวอร์โหลดของผู้ประกอบการหรือไม่หากเป็นประเภทที่กำหนดไว้"

ฉันคิดว่า == บน Generics จะใช้เวอร์ชันที่มีการโหลดมากเกินไป แต่การทดสอบต่อไปนี้แสดงให้เห็นเป็นอย่างอื่น น่าสนใจ ... ฉันชอบที่จะรู้ว่าทำไม! หากใครรู้กรุณาแบ่งปัน

namespace TestProject
{
 class Program
 {
    static void Main(string[] args)
    {
        Test a = new Test();
        Test b = new Test();

        Console.WriteLine("Inline:");
        bool x = a == b;
        Console.WriteLine("Generic:");
        Compare<Test>(a, b);

    }


    static bool Compare<T>(T x, T y) where T : class
    {
        return x == y;
    }
 }

 class Test
 {
    public static bool operator ==(Test a, Test b)
    {
        Console.WriteLine("Overloaded == called");
        return a.Equals(b);
    }

    public static bool operator !=(Test a, Test b)
    {
        Console.WriteLine("Overloaded != called");
        return a.Equals(b);
    }
  }
}

เอาท์พุต

Inline: Overloaded == เรียกว่า

สามัญ:

กดปุ่มใดก็ได้เพื่อดำเนินการต่อ . .

ติดตาม 2

ฉันต้องการชี้ให้เห็นว่าการเปลี่ยนวิธีเปรียบเทียบของฉันเป็น

    static bool Compare<T>(T x, T y) where T : Test
    {
        return x == y;
    }

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


ขอบคุณ ฉันไม่ได้สังเกตว่าคำสั่งนั้นเกี่ยวกับประเภทการอ้างอิงเท่านั้น
Hosam Aly

4
Re: การติดตาม 2: จริงๆแล้วคอมไพเลอร์จะเชื่อมโยงกับวิธีที่ดีที่สุดที่พบซึ่งในกรณีนี้ Test.op_Equal แต่ถ้าคุณมีคลาสที่มาจาก Test และแทนที่โอเปอเรเตอร์โอเปอเรเตอร์ของ Test จะยังคงถูกเรียกใช้
Hosam Aly

4
ฉันมีวิธีปฏิบัติที่ดีที่ฉันต้องการจะชี้ให้เห็นคือคุณควรทำการเปรียบเทียบที่เกิดขึ้นจริงภายในEqualsเมธอดoverridden (ไม่ใช่ใน==โอเปอเรเตอร์)
jpbochi

11
ความละเอียดเกินพิกัดเกิดขึ้นขณะรวบรวม ดังนั้นเมื่อเรามี==ระหว่างประเภททั่วไปTและTพบว่าเกินพิกัดที่ดีที่สุดให้สิ่งที่ข้อ จำกัด จะดำเนินการT(มีกฎพิเศษที่มันจะไม่กล่องชนิดค่าสำหรับนี้ (ซึ่งจะให้ผลลัพธ์ที่ไม่มีความหมาย) ดังนั้นจะต้องมี ข้อ จำกัด บางประการรับประกันได้ว่าเป็นประเภทอ้างอิง) ในการติดตาม 2 ของคุณหากคุณมาพร้อมกับDerivedTestวัตถุและDerivedTestมาจากTestแต่แนะนำการโอเวอร์โหลดใหม่==คุณจะมี "ปัญหา" อีกครั้ง โอเวอร์โหลดใดที่เรียกว่า "เผา" ลงใน IL ในเวลารวบรวม
Jeppe Stig Nielsen

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

292

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

แทนที่จะโทรเท่ากับจะเป็นการดีกว่าที่จะใช้IComparer<T>- และหากคุณไม่มีข้อมูลเพิ่มเติมEqualityComparer<T>.Defaultเป็นตัวเลือกที่ดี:

public bool Compare<T>(T x, T y)
{
    return EqualityComparer<T>.Default.Equals(x, y);
}

นอกเหนือจากสิ่งอื่นแล้วสิ่งนี้จะหลีกเลี่ยงการชกมวย / การตี


ขอบคุณ ฉันกำลังพยายามเขียนคลาส wrapper แบบง่าย ๆ ดังนั้นฉันแค่ต้องการมอบหมายการดำเนินการให้กับสมาชิกที่ปิดล้อมจริง แต่การรู้จัก EqualityComparer <T> เริ่มต้นช่วยเพิ่มมูลค่าให้ฉันอย่างแน่นอน :)
Hosam Aly

รองลงมาจอน; คุณอาจต้องการที่จะบันทึกความคิดเห็นใหม่ pobox vs yoda ในโพสต์ของฉัน
Marc Gravell

4
เคล็ดลับที่ดีเกี่ยวกับการใช้ EqualityComparer <T>
chakrit

1
+1 สำหรับการชี้ให้เห็นว่าสามารถเปรียบเทียบกับ null และสำหรับประเภทค่าที่ไม่เป็นโมฆะมันจะเป็นเท็จเสมอ
Jalal Said

@BlueRaja: ใช่เพราะมีกฎพิเศษสำหรับการเปรียบเทียบกับตัวอักษร null ดังนั้น "ไม่มีข้อ จำกัด ใด ๆ คุณสามารถเปรียบเทียบกับค่าว่าง แต่เป็นค่าว่างเท่านั้น" มันอยู่ในคำตอบแล้ว ดังนั้นทำไมสิ่งนี้ถึงไม่ถูกต้อง?
Jon Skeet

41

โดยทั่วไปEqualityComparer<T>.Default.Equalsควรทำงานด้วยสิ่งใดก็ตามที่ดำเนินการIEquatable<T>หรือมีEqualsการนำไปปฏิบัติอย่างมีเหตุผล

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

  • เท่ากับ (T value1, T value2)
  • NotEqual (T value1, T value2)
  • GreaterThan (ค่า T 1 ค่า T 2)
  • LessThan (T value1, T value2)
  • Greaterhan มาตรฐาน (ค่า T 1 ค่า T 2)
  • น้อยกว่าหรือมาตรฐาน (ค่า T 1, T ค่า 2)

ห้องสมุดที่น่าสนใจมาก! :) (หมายเหตุด้านข้าง: ฉันขอแนะนำให้ใช้ลิงก์ไปที่ www.yoda.arachsys.com เพราะ pobox อันหนึ่งถูกบล็อกโดยไฟร์วอลล์ในที่ทำงานของฉันหรือไม่เป็นไปได้ที่คนอื่นอาจเผชิญปัญหาเดียวกัน)
Hosam Aly

แนวคิดก็คือpobox.com/~skeetจะชี้ไปที่เว็บไซต์ของฉันเสมอ - แม้ว่าจะย้ายไปที่อื่นก็ตาม ฉันมักจะโพสต์ลิงก์ผ่าน pobox.com เพื่อประโยชน์ของลูกหลาน - แต่ปัจจุบันคุณสามารถทดแทน yoda.arachsys.com แทน
Jon Skeet

ปัญหาของ pobox.com คือบริการอีเมลทางเว็บ (หรือไฟร์วอลล์ของ บริษัท แจ้งว่า) ดังนั้นจึงถูกบล็อก นั่นเป็นเหตุผลที่ฉันไม่สามารถติดตามลิงก์ของมันได้
Hosam Aly

"อย่างไรก็ตามถ้า == และเท่ากับจะดำเนินการแตกต่างกันด้วยเหตุผลบางอย่าง" - สูบบุหรี่ศักดิ์สิทธิ์! อย่างไรก็ตามเป็นอย่างไร! บางทีฉันอาจต้องดูกรณีการใช้งานในทางตรงกันข้าม แต่ห้องสมุดที่มีความแตกต่างเท่ากับความหมายอาจมีปัญหาใหญ่กว่าปัญหากับยาสามัญ
Edward Brey

@ EdwardBrey คุณไม่ผิด มันคงจะดีถ้าคอมไพเลอร์สามารถบังคับใช้สิ่งนั้นได้ แต่ ...
Marc Gravell

31

มีคำตอบมากมายและไม่ใช่เพียงคำเดียวอธิบายว่าทำไม (ซึ่ง Giovanni ถามอย่างชัดเจน) ...

.NET generics ไม่ได้ทำตัวเหมือนแม่แบบ C ++ ใน C ++ เท็มเพลตการแก้ไขการโอเวอร์โหลดเกิดขึ้นหลังจากทราบพารามิเตอร์เท็มเพลตจริง

ใน. NET generics (รวมถึง C #) การแก้ปัญหาการโอเวอร์โหลดเกิดขึ้นโดยไม่ทราบถึงพารามิเตอร์ทั่วไปที่แท้จริง ข้อมูลเท่านั้นที่คอมไพเลอร์สามารถใช้เพื่อเลือกฟังก์ชั่นที่จะโทรมาจากข้อ จำกัด ประเภทกับพารามิเตอร์ทั่วไป


2
แต่ทำไมคอมไพเลอร์ไม่สามารถปฏิบัติต่อมันเป็นวัตถุทั่วไปได้? หลังจากทั้งหมด==ทำงานได้กับทุกประเภทไม่ว่าจะเป็นประเภทอ้างอิงหรือประเภทค่า นั่นควรเป็นคำถามที่ฉันไม่คิดว่าคุณจะตอบ
nawfal

4
@nawfal: ไม่จริง==ไม่สามารถใช้ได้กับทุกประเภทค่า ที่สำคัญกว่านั้นมันไม่มีความหมายเหมือนกันสำหรับทุกประเภทดังนั้นคอมไพเลอร์ไม่ทราบว่าต้องทำอย่างไรกับมัน
Ben Voigt

1
เบ็นใช่ฉันคิดถึงโครงสร้างที่กำหนดเองที่เราสามารถสร้างได้โดยไม่ต้องมีอะไร==เลย คุณสามารถรวมส่วนนั้นไว้ในคำตอบของคุณได้หรือไม่เพราะฉันคิดว่านั่นเป็นประเด็นหลักที่นี่
nawfal

12

คอมไพล์ไม่ทราบว่า T ไม่สามารถเป็น struct ได้ (ชนิดของค่า) ดังนั้นคุณต้องบอกว่ามันเป็นประเภทอ้างอิงเท่านั้นฉันคิดว่า:

bool Compare<T>(T x, T y) where T : class { return x == y; }

อาจเป็นเพราะถ้า T เป็นประเภทค่าอาจมีบางกรณีที่x == yรูปแบบไม่ดี - ในกรณีที่ประเภทไม่มีตัวดำเนินการ == ที่กำหนดไว้ สิ่งเดียวกันจะเกิดขึ้นสำหรับสิ่งนี้ซึ่งชัดเจนมากขึ้น:

void CallFoo<T>(T x) { x.foo(); }

นั่นก็ล้มเหลวเช่นกันเพราะคุณสามารถส่ง T ประเภทที่ไม่มีฟังก์ชั่น foo C # บังคับให้คุณเพื่อให้แน่ใจว่าทุกประเภทที่เป็นไปได้มักจะมีฟังก์ชั่น foo ที่ทำโดยประโยคที่


1
ขอขอบคุณสำหรับการชี้แจง. ฉันไม่ทราบว่าประเภทค่าไม่รองรับตัวดำเนินการ == นอกกรอบ
Hosam Aly

1
Hosam ฉันทดสอบกับ gmcs (โมโน) และมันมักจะเปรียบเทียบการอ้างอิง (นั่นคือมันไม่ได้ใช้ตัวดำเนินการที่กำหนดเป็นตัวเลือก == สำหรับ T)
Johannes Schaub - litb

มีข้อแม้หนึ่งข้อที่มีวิธีแก้ปัญหานี้: โอเปอเรเตอร์ == ไม่สามารถโอเวอร์โหลดได้ ดูคำถาม StackOverflowนี้
Dimitri C.

8

ปรากฏว่าไม่มีข้อ จำกัด ของคลาส:

bool Compare<T> (T x, T y) where T: class
{
    return x == y;
}

หนึ่งควรตระหนักว่าในขณะที่classมีข้อ จำกัดEqualsใน==สืบทอดจากผู้ประกอบการในขณะที่ของการแทนที่Object.Equals structValueType.Equals

โปรดทราบว่า:

bool Compare<T> (T x, T y) where T: struct
{
    return x == y;
}

ยังให้ข้อผิดพลาดคอมไพเลอร์เดียวกัน

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

bool Compare<T> (T x, T y)
{
    return x.Equals(y);
}

คุณรู้ว่าฉันทั้งหมด c # noob แต่ฉันคิดว่ามันล้มเหลวเพราะคอมไพเลอร์ไม่รู้จะทำอย่างไร เนื่องจาก T ยังไม่ทราบสิ่งที่ทำจะขึ้นอยู่กับประเภท T หากอนุญาตให้ใช้ประเภทค่า สำหรับการอ้างอิงการอ้างอิงจะถูกเปรียบเทียบโดยไม่คำนึงถึง T. หากคุณทำ. Equals ดังนั้น. Equal จะถูกเรียกใช้
Johannes Schaub - litb

แต่ถ้าคุณทำ == ในประเภทค่าประเภทของค่าไม่จำเป็นต้องใช้ตัวดำเนินการที่จำเป็น
Johannes Schaub - litb

นั่นทำให้เข้าใจได้ litb :) เป็นไปได้ที่ structs ที่ผู้ใช้กำหนดเองจะไม่ทำงานหนักเกินไป == ดังนั้นคอมไพเลอร์จึงล้มเหลว
Jon Limjap

2
วิธีการเปรียบเทียบครั้งแรกไม่ได้ใช้Object.Equalsแต่เป็นการทดสอบความเท่าเทียมอ้างอิง ตัวอย่างเช่นCompare("0", 0.ToString())จะคืนค่าเท็จเนื่องจากอาร์กิวเมนต์จะอ้างอิงถึงสตริงที่แตกต่างกันซึ่งทั้งคู่มีศูนย์เป็นอักขระตัวเดียวเท่านั้น
supercat

1
ผู้เยาว์ gotcha ในช่วงสุดท้ายนั้น - คุณไม่ได้ จำกัด ให้เป็น structs ดังนั้นNullReferenceExceptionอาจเกิดขึ้นได้
Flynn1179

6

ในกรณีของฉันฉันต้องการทดสอบหน่วยตัวดำเนินการความเสมอภาค ฉันต้องการเรียกรหัสภายใต้ตัวดำเนินการความเสมอภาคโดยไม่ต้องตั้งค่าประเภททั่วไปอย่างชัดเจน คำแนะนำสำหรับการEqualityComparerไม่เป็นประโยชน์ในฐานะที่EqualityComparerเรียกว่าEqualsวิธีการ แต่ไม่ได้เป็นผู้ประกอบการความเท่าเทียมกัน

LINQนี่คือวิธีการที่ฉันได้ทำงานนี้กับประเภททั่วไปโดยการสร้าง มันเรียกรหัสที่เหมาะสมสำหรับ==และ!=ผู้ประกอบการ:

/// <summary>
/// Gets the result of "a == b"
/// </summary>
public bool GetEqualityOperatorResult<T>(T a, T b)
{
    // declare the parameters
    var paramA = Expression.Parameter(typeof(T), nameof(a));
    var paramB = Expression.Parameter(typeof(T), nameof(b));
    // get equality expression for the parameters
    var body = Expression.Equal(paramA, paramB);
    // compile it
    var invokeEqualityOperator = Expression.Lambda<Func<T, T, bool>>(body, paramA, paramB).Compile();
    // call it
    return invokeEqualityOperator(a, b);
}

/// <summary>
/// Gets the result of "a =! b"
/// </summary>
public bool GetInequalityOperatorResult<T>(T a, T b)
{
    // declare the parameters
    var paramA = Expression.Parameter(typeof(T), nameof(a));
    var paramB = Expression.Parameter(typeof(T), nameof(b));
    // get equality expression for the parameters
    var body = Expression.NotEqual(paramA, paramB);
    // compile it
    var invokeInequalityOperator = Expression.Lambda<Func<T, T, bool>>(body, paramA, paramB).Compile();
    // call it
    return invokeInequalityOperator(a, b);
}

4

มีรายการ MSDN Connect สำหรับที่นี่

การตอบกลับของ Alex Turner เริ่มต้นด้วย:

น่าเสียดายที่พฤติกรรมนี้เกิดจากการออกแบบและไม่มีวิธีแก้ปัญหาที่ง่ายในการเปิดใช้งาน == พร้อมพารามิเตอร์ประเภทที่อาจมีประเภทของค่า


4

หากคุณต้องการให้แน่ใจว่าตัวดำเนินการประเภทที่กำหนดเองของคุณถูกเรียกว่าคุณสามารถทำได้ผ่านการสะท้อนกลับ รับชนิดโดยใช้พารามิเตอร์ทั่วไปของคุณและเรียกใช้ MethodInfo สำหรับโอเปอเรเตอร์ที่ต้องการ (เช่น op_Equality, op_Inequality, op_LessThan ... )

var methodInfo = typeof (T).GetMethod("op_Equality", 
                             BindingFlags.Static | BindingFlags.Public);    

จากนั้นดำเนินการตัวดำเนินการโดยใช้วิธีการเรียกใช้เมธอด InvInfo และส่งผ่านวัตถุเป็นพารามิเตอร์

var result = (bool) methodInfo.Invoke(null, new object[] { object1, object2});

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


3

ฉันเขียนฟังก์ชันต่อไปนี้เพื่อดู msdn ล่าสุด สามารถเปรียบเทียบสองวัตถุxและy:

static bool IsLessThan(T x, T y) 
{
    return ((IComparable)(x)).CompareTo(y) <= 0;
}

4
คุณสามารถกำจัด booleans ของคุณและเขียนreturn ((IComparable)(x)).CompareTo(y) <= 0;
aloisdg ย้ายไป codidact.com

1

bool Compare(T x, T y) where T : class { return x == y; }

ด้านบนจะทำงานได้เนื่องจาก == ได้รับการดูแลในกรณีที่ประเภทการอ้างอิงที่ผู้ใช้กำหนด
ในกรณีของประเภทค่า == สามารถแทนที่ได้ ในกรณีนี้ควรกำหนด "! =" ด้วย

ฉันคิดว่านั่นอาจเป็นเหตุผลที่ทำให้ไม่สามารถเปรียบเทียบโดยใช้ "=="


2
ขอบคุณ ฉันเชื่อว่าประเภทการอ้างอิงยังสามารถแทนที่ตัวดำเนินการได้เช่นกัน แต่เหตุผลความล้มเหลวชัดเจนแล้ว
Hosam Aly

1
==โทเค็นจะใช้สำหรับผู้ประกอบการที่แตกต่างกันสอง หากสำหรับตัวถูกดำเนินการประเภทที่มีอยู่เกินพิกัดที่เข้ากันได้ของผู้ประกอบการความเท่าเทียมกันที่เกินจะใช้ มิฉะนั้นหากตัวถูกดำเนินการทั้งสองเป็นประเภทการอ้างอิงที่เข้ากันได้จะใช้การเปรียบเทียบการอ้างอิง หมายเหตุว่าในCompareวิธีการข้างต้นคอมไพเลอร์ไม่สามารถบอกได้ว่าความหมายแรกก่อน แต่สามารถบอกความหมายที่สองนำไปใช้เพื่อให้==โทเค็นจะใช้หลังแม้ว่าToverloads ประกอบการตรวจสอบความเท่าเทียมกัน (เช่นถ้าเป็นของประเภทString )
supercat

0

.Equals()งานสำหรับฉันในขณะที่TKeyเป็นประเภททั่วไป

public virtual TOutputDto GetOne(TKey id)
{
    var entity =
        _unitOfWork.BaseRepository
            .FindByCondition(x => 
                !x.IsDelete && 
                x.Id.Equals(id))
            .SingleOrDefault();


    // ...
}

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