หมายเหตุ: สิ่งนี้ดูเหมือนจะได้รับการแก้ไขในRoslyn
คำถามนี้เกิดขึ้นเมื่อการเขียนคำตอบของฉันคนนี้ซึ่งพูดคุยเกี่ยวกับการเชื่อมโยงกันของผู้ประกอบการด้วย null coalescing
เช่นเดียวกับการเตือนความคิดของตัวดำเนินการ null-coalescing คือการแสดงออกของแบบฟอร์ม
x ?? y
ประเมินก่อนx
จากนั้น:
- หากค่า
x
เป็น nully
จะถูกประเมินและนั่นคือผลลัพธ์สุดท้ายของการแสดงออก - หากค่าของ
x
ไม่ใช่ค่าว่างy
จะไม่ถูกประเมินและค่าของx
เป็นผลลัพธ์สุดท้ายของการแสดงออกหลังจากแปลงเป็นประเภทการรวบรวมเวลาy
หากจำเป็น
ตอนนี้มักจะมีความจำเป็นสำหรับการแปลงไม่มีหรือมันเป็นเพียงแค่จากประเภท nullable ที่ไม่ใช่ nullable หนึ่ง - ปกติชนิดที่เหมือนกันหรือเพียงแค่จาก (พูด) เพื่อint?
int
อย่างไรก็ตามคุณสามารถสร้างตัวดำเนินการแปลงโดยนัยของคุณเองและสิ่งเหล่านี้จะถูกใช้เมื่อจำเป็น
สำหรับกรณีง่าย ๆx ?? y
ฉันไม่เห็นพฤติกรรมแปลก ๆ อย่างไรก็ตามด้วยความที่(x ?? y) ?? z
ฉันเห็นพฤติกรรมที่สับสน
นี่คือโปรแกรมทดสอบสั้น ๆ แต่สมบูรณ์ - ผลลัพธ์อยู่ในความคิดเห็น:
using System;
public struct A
{
public static implicit operator B(A input)
{
Console.WriteLine("A to B");
return new B();
}
public static implicit operator C(A input)
{
Console.WriteLine("A to C");
return new C();
}
}
public struct B
{
public static implicit operator C(B input)
{
Console.WriteLine("B to C");
return new C();
}
}
public struct C {}
class Test
{
static void Main()
{
A? x = new A();
B? y = new B();
C? z = new C();
C zNotNull = new C();
Console.WriteLine("First case");
// This prints
// A to B
// A to B
// B to C
C? first = (x ?? y) ?? z;
Console.WriteLine("Second case");
// This prints
// A to B
// B to C
var tmp = x ?? y;
C? second = tmp ?? z;
Console.WriteLine("Third case");
// This prints
// A to B
// B to C
C? third = (x ?? y) ?? zNotNull;
}
}
ดังนั้นเราจึงมีสามประเภทค่าที่กำหนดเองA
, B
และC
มีการแปลงจาก A ไป B, A ถึง C และ B เพื่อซี
ฉันสามารถเข้าใจทั้งกรณีที่สองและกรณีที่สาม ... แต่ทำไมมีการแปลง A เป็น B พิเศษในกรณีแรก โดยเฉพาะอย่างยิ่งผมจริงๆได้คาดว่ากรณีแรกและกรณีที่สองจะเป็นสิ่งเดียวกัน - มันเป็นเพียงแค่การสกัดการแสดงออกเป็นตัวแปรท้องถิ่นหลังจากทั้งหมด
ผู้รับใด ๆ ที่เกิดขึ้น? ฉันลังเลอย่างยิ่งที่จะร้องไห้ "บั๊ก" เมื่อพูดถึงคอมไพเลอร์ C # แต่ฉันนิ่งงันว่าเกิดอะไรขึ้น ...
แก้ไข: เอาล่ะนี่เป็นตัวอย่างที่น่าสนใจมากขึ้นของสิ่งที่เกิดขึ้นขอบคุณคำตอบของตัวกำหนดค่าซึ่งทำให้ฉันมีเหตุผลเพิ่มเติมที่จะคิดว่ามันเป็นข้อผิดพลาด แก้ไข: ตัวอย่างไม่จำเป็นต้องมีผู้ประกอบการ null รวมสองตอนนี้ ...
using System;
public struct A
{
public static implicit operator int(A input)
{
Console.WriteLine("A to int");
return 10;
}
}
class Test
{
static A? Foo()
{
Console.WriteLine("Foo() called");
return new A();
}
static void Main()
{
int? y = 10;
int? result = Foo() ?? y;
}
}
ผลลัพธ์ของสิ่งนี้คือ:
Foo() called
Foo() called
A to int
ความจริงที่Foo()
ได้รับการเรียกสองครั้งที่นี่ทำให้ฉันประหลาดใจอย่างมาก - ฉันไม่เห็นเหตุผลที่จะต้องประเมินการแสดงออกสองครั้ง
C? first = ((B?)(((B?)x) ?? ((B?)y))) ?? ((C?)z);
ลองใช้สายนี้กับทุกแปลงโดยปริยาย: คุณจะได้รับ:Internal Compiler Error: likely culprit is 'CODEGEN'
(("working value" ?? "user default") ?? "system default")