Câu hỏi này đã được đại tu hoàn toàn vì lợi ích của việc giải thích kỹ lưỡng.C# 6.0 Null Tuyên truyền điều hành và phân bổ tài sản
tôi đã nhận thấy những gì dường như là khá hạn chế kém của các nhà điều hành công tác tuyên truyền null trong C# 6.0 ở chỗ bạn không thể gọi bất động sản setters chống lại một đối tượng mà đã được tuyên truyền null (mặc dù bạn có thể gọi bất động sản getters đối với một đối tượng đã được vô hiệu hóa). Như bạn sẽ thấy từ IL được tạo ra (mà tôi đã phản ánh vào C#), không có gì nên hạn chế khả năng gọi trình định vị thuộc tính bằng cách sử dụng tuyên truyền vô hiệu.
Để bắt đầu, tôi đã tạo một lớp đơn giản, với cả hai phương thức Get/Set kiểu Java và thuộc tính có quyền truy cập công cụ getter/setter công cộng.
public class Person
{
public Person(string name, DateTime birthday)
{
Name = name;
}
public string Name { get; set; }
public void SetName(string name)
{
Name = name;
}
public string GetName()
{
return Name;
}
}
Tôi đã kiểm tra khả năng tuyên truyền vô hiệu trong lớp thử nghiệm sau đây.
public class Program
{
public static void Main(string[] args)
{
Person person = new Person("Joe Bloggs", DateTime.Parse("01/01/1991"));
// This line doesn't work - see documented error below
person?.Name = "John Smith";
person?.SetName("John Smith");
string name = person?.Name;
}
}
Phía bên tay trái của một bài tập phải là một biến, tài sản hoặc indexer.
Tuy nhiên, bạn có thể nhận thấy rằng cách Java đặt tên bằng cách gọi SetName(...)
hoạt động và bạn cũng có thể nhận thấy giá trị của thuộc tính được truyền không có tác dụng.
Chúng ta hãy nhìn vào C# được tạo ra từ mã này:
public static void Main(string[] args)
{
Person person = new Person("Joe Bloggs", DateTime.Parse("01/01/1991"));
if (person != null)
{
person.SetName("John Smith");
}
string arg_33_0 = (person != null) ? person.Name : null;
}
Chú ý rằng khi sử dụng chống lại các phương pháp SetName
, tuyên truyền rỗng biến đổi đến một if
tuyên bố thẳng thắn, và rằng khi sử dụng chống lại các Name
property getter, một toán tử bậc ba được sử dụng để nhận giá trị Name
hoặc null
. Một điều tôi đã nhận thấy ở đây là sự khác biệt về hành vi giữa việc sử dụng câu lệnh if
và sử dụng toán tử bậc ba: khi sử dụng trình setter, sử dụng câu lệnh if
, trong khi sử dụng toán tử ternary thì không.
public static void Main(string[] args)
{
Person person = null;
if (person != null)
{
person.Name = "John Smith";
}
person.Name = (person != null) ? "John Smith" : null;
}
Trong ví dụ này tôi đang sử dụng cả một tuyên bố if
và các nhà điều hành ternary để kiểm tra xem người là null
trước khi cố gắng để gán cho bất động sản Name
của nó. tuyên bố if
hoạt động như mong đợi; tuyên bố sử dụng toán tử bậc ba thất bại, như mong đợi
Tham chiếu đối tượng không được đặt thành thể hiện của đối tượng.
Theo tôi, giới hạn xuất phát từ khả năng chuyển đổi không thành công của C# 6.0 thành câu lệnh if
hoặc biểu thức ba giây. Nếu nó được thiết kế để chỉ sử dụng các câu lệnh if
, việc gán thuộc tính sẽ hoạt động thông qua việc truyền null.
Cho đến nay, tôi chưa thấy một đối số thuyết phục nào về lý do tại sao KHÔNG NÊN này có thể, do đó tôi vẫn đang tìm câu trả lời!
Đó không phải là cách nó hoạt động. Toán tử * trả về * một giá trị sau khi kiểm tra null. –
Không có gì sai với toán tử - trong thực tế, nhiều ngôn ngữ có các toán tử tương tự nhau. Nó chỉ đơn giản là không làm những gì bạn nghĩ rằng nó, cũng không phải tên của nó đề nghị này. Trong thực tế, nó sẽ là một vấn đề nếu nó đã hành động theo cách này - các nhà điều hành sẽ cư xử khác nhau tùy thuộc vào việc nó được ở bên trái hoặc bên phải của một nhiệm vụ. –
Tại sao bạn nghĩ rằng 'null tuyên truyền' đã làm với nhiệm vụ? Nó sẽ * rõ ràng hơn các tên tương tự trong các ngôn ngữ khác (ví dụ như an toàn vô giá như được đề xuất cho Java, điều hướng an toàn trong Groovy, gọi an toàn trong Kotlin) mà nó không gán bất cứ thứ gì nhưng trả về (truyền) null nếu áp dụng trên một đối tượng null –