2009-06-04 28 views
6

Tôi đã luôn luôn giả định rằng DbNull.value là một singleton. Và như vậy, bạn có thể làm những việc như thế này:Tại sao DbNull của tôi không phải là một singleton khi tôi deserialise nó bằng cách sử dụng XmlSerialiser?

VB.NET:

If someObject Is DbNull.Value Then 
    ... 
End if 

C#:

If (someObject == DbNull.Value) 
{ 
    ... 
} 

Nhưng gần đây, tôi đăng một trường hợp sử dụng DBNull XmlSerialiser và đột nhiên nó không phải là một singleton nữa. Loại hoạt động so sánh (như C# 's (obj là DBNull)) làm việc OK mặc dù.

Mã sau:

[Serializable, System.Xml.Serialization.XmlInclude(typeof(DBNull))] 
public class SerialiseMe 
{ 
    public SerialiseMe() { } 

    public SerialiseMe(object value) 
    { 
     this.ICanBeDbNull = value; 
    } 
    public Object ICanBeDbNull { get; set; } 
} 

public void Foo() 
{ 
    var serialiseDbNull = new SerialiseMe(DBNull.Value); 
    var serialiser = new System.Xml.Serialization.XmlSerializer(typeof(SerialiseMe)); 
    var ms = new System.IO.MemoryStream(); 
    serialiser.Serialize(ms, serialiseDbNull); 
    ms.Seek(0, System.IO.SeekOrigin.Begin); 
    var deSerialisedDbNull = (SerialiseMe)serialiser.Deserialize(ms); 

    // Is false, WTF! 
    var equalsDbNullDeserialised = deSerialisedDbNull.ICanBeDbNull == DBNull.Value; 
    // Is false, WTF! 
    var refEqualsDbNullDeserialised = object.ReferenceEquals(deSerialisedDbNull.ICanBeDbNull, DBNull.Value); 
    // Is true. 
    var convertIsDbNullDeserialised = Convert.IsDBNull(deSerialisedDbNull.ICanBeDbNull); 
    // Is true. 
    var isIsDbNullDeserialised = deSerialisedDbNull.ICanBeDbNull is DBNull; 

} 

Tại sao đây là trường hợp? Và nó xảy ra như thế nào? Và nó có thể xảy ra với bất kỳ trường tĩnh nào khác không?

PS: Tôi biết mẫu mã VB đang thực hiện so sánh tham chiếu và C# đang gọi Object.Equals. Cả hai đều có cùng một hành vi với DBNull. Tôi thường làm việc với VB.

+0

Tôi đã làm rối tung một vài thứ tương tự trong vài giờ ngay bây giờ ... Tôi thậm chí còn không thử IS DBNull. – Feign

Trả lời

7

Mặc dù DBNull.Valuestatic readonly và chỉ tồn tại dưới dạng một trường hợp ... khi bạn hủy tuần tự hóa, mã tuần tự sẽ tạo một phiên bản mới của lớp DBNull từ 'dữ liệu' trong luồng. Kể từ khi DBNull.Value chỉ đơn giản là một ví dụ DBNull, không có cách nào để serialization biết rằng đó là một trường hợp 'đặc biệt'.

LƯU Ý:
Đối với lý do tương tự, nếu bạn thực hiện lớp riêng bạn với một 'singleton' dụ mà bạn serialize và sau đó de-serialize bạn sẽ nhận được chính xác những hành vi tương tự. Mặc dù cá thể deserialized sẽ không thể phân biệt được từ bản gốc, chúng sẽ không được cùng một ví dụ.

+0

Bah! Một pox trên mã serialization ma thuật. Ta cho câu trả lời mặc dù. – ligos

+0

Không phải tất cả ma thuật đều có thể là màu trắng ...;) – jerryjvl

1

Mã C# của bạn không bằng nhau gọi phương thức .Equals. Với ra đã thử nghiệm nó Im thực sự khá chắc chắn nếu bạn thay

someObject == DbNull.Value 

với

DbNull.Value.Equals(someObject) 

nó sẽ cung cấp cho bạn những kết quả mong đợi. Đối với một số bên trong về toán tử bình đẳng và phương thức Equals, hãy xem: Eric Lipperts blog post on that subject

+0

Tôi không thử kết hợp của Equals() trước đây, nhưng nó không hoạt động. Object.RefEquals (obj, DbNull.Value), Object.Equals (obj, DbNull.Value), obj == DBNull.Value, và DbNull.Value.Equals (obj) tất cả trả về false sau khi deserialisation. – ligos

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