2009-08-26 51 views
9

Điều này có vẻ giống như một lỗi với tôi ...C# Thuộc tính tự động - Vẫn còn null sau + =?

Tôi chấp nhận rằng tính tự động, được xác định như vậy:

public decimal? Total { get; set; } 

sẽ được null khi chúng được truy cập đầu tiên. Chúng chưa được khởi tạo, vì vậy tất nhiên chúng không có giá trị.

Nhưng, ngay cả sau khi đặt giá trị của chúng thông qua + =, số thập phân này? vẫn còn null. Vì vậy, sau:

Total += 8; 

Tổng số vẫn không có giá trị. Làm thế nào điều này có thể chính xác? Tôi hiểu rằng nó đang làm một (null + 8), nhưng dường như lạ mà nó không nhận rằng nó có nghĩa là nó chỉ nên được đặt thành 8 ...

phụ lục:

tôi đã "null + 8 "điểm trong câu hỏi của tôi - nhưng lưu ý rằng nó hoạt động với chuỗi. Vì vậy, nó không null + "hello" tốt, và trả về "hello". Vì vậy, đằng sau hậu trường, nó đang khởi tạo chuỗi thành một đối tượng chuỗi với giá trị "hello". Hành vi phải giống nhau đối với các loại khác, IMO. Nó có thể là do một chuỗi có thể chấp nhận một giá trị rỗng như một giá trị, nhưng vẫn còn, một chuỗi rỗng không phải là một đối tượng được khởi tạo, đúng không?

Có lẽ nó chỉ vì một chuỗi không phải là một nullable ...

+7

"Chúng chưa được khởi tạo, vì vậy tất nhiên chúng không có giá trị." Đây là mấu chốt của sự nhầm lẫn của bạn. Các thuộc tính được tự động gán ban đầu, trong trường hợp này, là null. Bạn đang lý luận từ một sai lầm: rằng tài sản là chưa được giao. * Thuộc tính ban đầu được gán * Không có bất kỳ thứ gì như "thuộc tính chưa được gán" trong C#. –

+1

Sự khác biệt thú vị. Cũng thú vị là bạn có thể tìm thấy hàng ngàn ví dụ về những người đề cập đến các giá trị "được khởi tạo thành null" là "chưa được khởi tạo". Vì vậy, có lẽ đó là một quan niệm sai lầm phổ biến. Một điều tôi tò mò - nếu chúng ta có vấn đề này, nơi chúng ta không muốn tạo ra "null + 8 = 8" hoặc "null && true == true", tại sao nó lại không bị loại trừ khi các kiểu này của mọi thứ được thực hiện? Dường như điều đó có thể có thể ngăn chặn một số khó khăn để gỡ lỗi. –

Trả lời

30
public decimal? Total { get; set; } 

Hãy suy nghĩ về null như "không rõ giá trị". Nếu bạn có số lượng không rõ và bạn thêm 8 số nữa, bạn hiện có bao nhiêu người?

Trả lời: không xác định.

Các thao tác trên biến Nullable

trường hợp hoạt động trên giá trị chưa biết cung cấp cho bạn thể biết được kết quả.

public bool? State { get; set; } 

Các câu sau đây có thể biết được giải pháp mặc dù chúng chứa biết giá trị:

State = null; 
nextState = State & false;   // always equals false 
nextState = State & true;   // still unknown (null) 

nextState = State | true;   // always true 
nextState = State | false;   // still unknown (null) 

Xem mô hình?

Tất nhiên, nếu bạn muốnTotal là tương đương (tương đương) đến 0 khi nó là null, bạn có thể sử dụng vô điều hành coalescing và viết một cái gì đó như thế này:

Total = (Total ?? 0) + 8; 

Đó sẽ sử dụng giá trị của Total trong phương trình của bạn trừ nó là null, trong trường hợp này nó sẽ sử dụng các giá trị 0.

+0

Vâng, tôi cho rằng điều này có ý nghĩa. Chỉ có vẻ sôi nổi. :) –

+0

Ồ, và cuộc gọi tốt về nhà điều hành kết hợp. –

+0

'Tổng số = (Tổng cộng 0) + 8;' có thể được viết lại thành 'Tổng = Tổng cộng.GetValueOrDefault (0) + 8;' trong phiên bản .NET 4.5+ –

6
Null + 8 = Null 

Bạn sẽ cần phải cài đặt nó với zero trước.

+1

Vâng, tôi biết đó là giải pháp, tôi chỉ nghĩ rằng nó câm. :) –

+0

tại sao nó câm? null! = 0 –

+0

Vì nó phản trực giác, ít nhất là với tôi. Nếu nó là trình biên dịch của tôi, tôi đã đưa ra giả định (đặc biệt là với một thuộc tính _automatic_) nếu bạn có giá trị chưa được khởi tạo và bạn thêm vào nó, nó sẽ chỉ nhận giá trị gia tăng. Nhưng, có lẽ có một số trường hợp loại giả định này sẽ gây ra vấn đề, ai biết được. –

5

null nghĩa giá trị không rõ,

unknown value + known value = still unknown value 
+0

Tôi hiểu những gì một null là, nhưng có vẻ như với tôi rằng nó sẽ là một giả định an toàn rằng null + 8 sẽ bằng 8. Nhưng, tôi đoán tôi chỉ là sai. :) –

+0

Bạn thực sự sai :) Nếu 'null' bằng '0' thì điểm nào có thể là' null'? Lưu ý rằng nếu bạn định nghĩa thuộc tính của bạn như một kiểu không null (loại bỏ dấu '?') Thì nó sẽ có giá trị mặc định cho kiểu thập phân mà AFAIK bằng 0 và bạn sẽ có thể sử dụng mã '+ = 8' của bạn. – RaYell

+0

Haha - :) Vâng, tôi đã nhận thấy giá trị mặc định với các đạo cụ tự động trước đây. Tôi không nói rằng null nên bằng không, chỉ cần rằng nếu bạn có một giá trị khởi tạo và bạn thêm nó vào một null, nó có ý nghĩa với tôi rằng lĩnh vực này sẽ chỉ nhận giá trị khởi tạo. –

0

để thiết lập giá trị của Tổng chỉ là

Total = 8; 

tôi sẽ khuyên bạn nên đọc lên trên Nullable Types để hiểu cách họ làm việc. Bạn có thể kiểm tra xem thuộc tính có giá trị hay không bằng cách sử dụng HasValue.

Từ MSDN:

nhà khai thác

Các unary và nhị phân được xác định trước nhà khai thác và bất kỳ người dùng định nghĩa nhà khai thác mà tồn tại với nhiều loại giá trị cũng có thể được sử dụng bởi các loại nullable. Các toán tử này tạo ra một giá trị null nếu toán hạng là null; nếu không, toán tử sử dụng giá trị chứa để tính kết quả.Ví dụ:

int? a = 10; 
int? b = null; 

a++;   // Increment by 1, now a is 11. 
a = a * 10; // Multiply by 10, now a is 110. 
a = a + b; // Add b, now a is null. 
+0

Cảm ơn. Tôi đã sử dụng các kiểu nullable khá nhiều, và đã chạy vào vấn đề này với việc khởi tạo thuộc tính tự động khá một chút, nhưng không bao giờ bận tâm hỏi tại sao. Tôi cho rằng nó có ý nghĩa, mặc dù tôi không biết nếu tôi đã làm theo cách đó ... –

+0

Có một phần tốt về các loại Nullable trong C# trong chiều sâu, trong số các chi tiết thú vị khác chủ yếu là C# 3, nhưng cũng là một ít C# 1 và nhiều hơn một chút về C# 2. Một cuốn sách tuyệt vời thực sự. –

+0

Toàn bộ ý tưởng về các kiểu nullable là bạn có thể gán giá trị null cho các kiểu giá trị :) –

2

Từ MSDN:

Khi bạn thực hiện so sánh với loại nullable, nếu giá trị của một trong những các loại nullable là null và khác không phải là, tất cả so sánh đánh giá thành sai trừ! = (không bằng nhau). Nó quan trọng là không giả định rằng vì một so sánh cụ thể trả về false, trường hợp ngược lại trả về true.

Vì vậy, nó hoạt động như dự định.

3

Dưới đây là một lớp lót để khởi tạo nó trên cuộc gọi đầu tiên và tăng nó sau đó:

public void InitializeOrIncrement(decimal value) 
    { 
     // if Total is null then initialize, otherwise increment 
     Total = (Total == null) ? value : Total + value; 
    } 

    public decimal? Total { get; set; } 
0

Null i không giống như số không. Zero cộng tám là tám ... nhưng null cộng tám? Luôn luôn rỗng. Cũng giống như vô cùng cộng với mọi thứ vẫn vô cùng - nó không xác định.

Bạn sẽ thấy rằng điều này hoàn toàn đúng với giá trị rỗng. Mỗi cơ sở dữ liệu (ít nhất là tôi đã từng làm việc với) sẽ cho bạn kết quả tương tự.

+0

Tính vô cùng + x = vô cùng là một cách tốt để đặt nó. –

0

số thập phân công khai?Tổng số {get; bộ; }

Điều gì đó giống như công việc này? Một số loại kích thích tự động nếu giá trị chưa được đặt.

public decimal? Total 
{ 
    get { return this.totalValue;} 
    set 
    { 
    if(totalValue == null) { this.totalValue = 0;} 
    this.totalValue = value; 
    } 
} 

private decimal? totalValue; 
+0

... nhưng nếu bạn không sử dụng các thuộc tính được tự động triển khai thì tại sao không chỉ khởi tạo trường sao lưu của bạn như là một phần của khai báo? 'số thập phân riêng? totalValue = 0; ' – STW

+0

Vâng, hãy đối mặt với nó, lý do duy nhất tôi sử dụng các thuộc tính tự động là lười biếng khi gõ. (Không phải đối tượng đánh máy - chỉ cần gõ ngón tay!) Nếu tôi sẽ chia nó ra, tôi sẽ chỉ mặc định nó để 0. –

+0

Yooder, bởi vì anh ta có thể không muốn giá trị là 0, anh ta có thể muốn nó là null. Robert, không thực sự nếu ai đó đặt Total thành null, nó sẽ được đặt thành 0, và sau đó đặt lại thành null trong trường hợp này, vì 'value' sẽ là null. 0 chỉ được sử dụng như là một initalizer lười biếng. – Ian

1

Tôi biết rằng nó có ý nghĩa để làm

public decimal? Total { get; set; } 

Total = (Total ?? 0) + 8; 

nhưng wouldnt nó chỉ là dễ dàng hơn để làm:

public decimal Total { get; set; } 

giá trị ban đầu của Tổng là 0

+0

Vâng, đây thực sự là những gì tôi đã thay đổi mã của mình. Đối với một tổng số chạy, nó thực sự không có ý nghĩa cho tổng số bao giờ bằng null thực sự, nếu bạn nghĩ về nó. Nó có ý nghĩa đối với các mục được thêm vào để có khả năng là null, nhưng tổng số có thể luôn luôn là> = 0. Thảo luận thú vị mặc dù. –

1

Như khác mọi người đã chỉ ra, null không bằng 0. Mặc dù nó có vẻ thuận tiện hơn cho một số nguyên null để mặc định bằng không trong thời gian dài nó có khả năng tạo ra kết quả lạ mà bạn có thể không phát hiện cho đến khi quá muộn.

Ví dụ: giả sử một trong các nguồn cấp dữ liệu của bạn không thành công và điền tập hợp kết quả của bạn bằng các giá trị rỗng. Các phép tính của bạn sẽ xử lý các giá trị rỗng là 0 và tiếp tục tạo ra các kết quả. Khi các con số vẫn còn sắp ra mắt, mặc dù chúng có thể sai, bạn có thể không bao giờ nhận thấy rằng một cái gì đó đã đi sai một cách nghiêm trọng.

Các vấn đề liên quan