Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why isn't my DbNull a singleton when I deserialise it using XmlSerialiser?

I've always assumed that DbNull.value was a singleton. And thus you could do things like this:

VB.NET:

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

C#:

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

But recently, I serialised a DbNull instance using the XmlSerialiser and suddenly it wasn't a singleton any more. Type comparison operations (like C#'s (obj is DBNull)) work OK though.

Code follows:

[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;

}

Why is this the case? And how does it happen? And can it possibly happen with any other static fields?

PS: I am aware the VB code sample is doing a reference comparison and c# is calling Object.Equals. Both have the same behaviour with DBNull. I usually work with VB.

like image 218
ligos Avatar asked Jun 04 '09 05:06

ligos


2 Answers

Although DBNull.Value is a static readonly and only exists as a single instance... when you de-serialize, the serialization code would be creating a new instance of the class DBNull from the 'data' in the stream. Since the DBNull.Value is simply a DBNull instance, there is no way for serialization to know that it is a 'special' instance.

NOTE:
For the same reason, if you make your own class with a 'singleton' instance that you serialize and then de-serialize you will get exactly the same behaviour. Although the deserialized instance will be indistinguishable from the original instance, they will not be the same instance.

like image 133
jerryjvl Avatar answered Nov 17 '22 07:11

jerryjvl


Your c# code does not equal calling the .Equals method. With out having tested it Im actually pretty sure if you substituted

someObject == DbNull.Value

with

DbNull.Value.Equals(someObject) 

it would give you the expected result. For some insides on the equality operator and the Equals method take a look at: Eric Lipperts blog post on that subject

like image 1
Rune FS Avatar answered Nov 17 '22 06:11

Rune FS