Lưu ý: điều này dường như đã được sửa ở Roslyn
Câu hỏi này xuất hiện khi viết câu trả lời của tôi cho câu hỏi này , trong đó nói về sự kết hợp của toán tử hợp nhất null .
Cũng như một lời nhắc nhở, ý tưởng của toán tử hợp nhất null là biểu thức của biểu mẫu
x ?? y
đầu tiên đánh giá x
, sau đó:
- Nếu giá trị
x
là null,y
được ước tính và đó là kết quả cuối cùng của biểu thức - Nếu giá trị của
x
là không null,y
là không được đánh giá, và giá trị củax
là kết quả cuối cùng của biểu thức, sau khi chuyển đổi các loại thời gian biên dịchy
nếu cần thiết
Bây giờ thường không cần chuyển đổi, hoặc chỉ là từ loại không thể thành loại không thể chuyển đổi - thường là các loại giống nhau hoặc chỉ từ (nói) int?
thành int
. Tuy nhiên, bạn có thể tạo các toán tử chuyển đổi ẩn của riêng mình và các toán tử chuyển đổi được sử dụng khi cần thiết.
Đối với trường hợp đơn giản x ?? y
, tôi chưa thấy bất kỳ hành vi kỳ quặc nào. Tuy nhiên, với (x ?? y) ?? z
tôi thấy một số hành vi khó hiểu.
Đây là một chương trình thử nghiệm ngắn nhưng đầy đủ - kết quả có trong các bình luận:
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;
}
}
Vì vậy, chúng tôi có ba loại giá trị tùy chỉnh, A
, B
và C
, với các chuyển đổi từ A đến B, A đến C, và B đến C.
Tôi có thể hiểu cả trường hợp thứ hai và trường hợp thứ ba ... nhưng tại sao lại có thêm chuyển đổi từ A sang B trong trường hợp đầu tiên? Đặc biệt, tôi thực sự đã mong đợi trường hợp đầu tiên và trường hợp thứ hai giống nhau - đó chỉ là trích xuất một biểu thức thành một biến cục bộ.
Bất kỳ người tham gia vào những gì đang xảy ra? Tôi vô cùng ngần ngại khi khóc "lỗi" khi nói đến trình biên dịch C #, nhưng tôi đã bối rối vì những gì đang diễn ra ...
EDIT: Được rồi, đây là một ví dụ khó hiểu hơn về những gì đang diễn ra, nhờ câu trả lời của nhà cấu hình, điều này cho tôi thêm lý do để nghĩ rằng đó là một lỗi. EDIT: Mẫu thậm chí không cần hai toán tử hợp nhất null bây giờ ...
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;
}
}
Đầu ra của nó là:
Foo() called
Foo() called
A to int
Thực tế Foo()
được gọi hai lần ở đây là vô cùng ngạc nhiên đối với tôi - tôi không thể thấy bất kỳ lý do nào để biểu thức được đánh giá hai lần.
C? first = ((B?)(((B?)x) ?? ((B?)y))) ?? ((C?)z);
. Bạn sẽ nhận được:Internal Compiler Error: likely culprit is 'CODEGEN'
(("working value" ?? "user default") ?? "system default")