2009-06-04 9 views
6

Siempre he supuesto que DbNull.value era un singleton. Y por lo tanto se podía hacer cosas como esta:¿Por qué mi DbNull no es un singleton cuando lo deserializo usando XmlSerialiser?

VB.NET:

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

C#:

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

Pero recientemente, serializado una instancia DBNull utilizando el XmlSerialiser y de repente no estaba un singleton más. Las operaciones de comparación de tipos (como C# 's (obj es DBNull)) funcionan bien.

Código sigue:

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

} 

¿Por qué es este el caso? ¿Y cómo sucede? ¿Y puede suceder posiblemente con cualquier otro campo estático?

PD: Soy consciente de que la muestra del código VB está haciendo una comparación de referencia y C# está llamando a Object.Equals. Ambos tienen el mismo comportamiento con DBNull. Normalmente trabajo con VB.

+0

He estado jugando con algo bastante similar desde hace unas horas ... Ni siquiera pensé en probar IS DBNull. – Feign

Respuesta

7

Aunque DBNull.Value es una static readonly y sólo existe como una sola instancia ... cuando serializar-DE, el código de serialización sería la creación de una nueva instancia de la clase DBNull del 'datos' en la corriente. Como el DBNull.Value es simplemente una instancia de DBNull, no hay forma de que la serialización sepa que se trata de una instancia 'especial'.

NOTA:
Por la misma razón, si usted hace su propia clase con una instancia 'Singleton' que serializa y luego des-serializar obtendrá exactamente el mismo comportamiento. Aunque la instancia deserializada será indistinguible de la instancia original, no serán la misma instancia.

+0

¡Bah! Una viruela en el código de serialización mágica. Ta por la respuesta sin embargo. – ligos

+0

No toda la magia puede ser blanca ...;) – jerryjvl

1

Su código C# no es igual a llamar al método .Equals. Con fuera de haber probado que estoy realmente muy seguro de si sustituiste

someObject == DbNull.Value 

con

DbNull.Value.Equals(someObject) 

le daría el resultado esperado. Para algunos aspectos del operador de igualdad y el método Equals, échele un vistazo a: Eric Lipperts blog post on that subject

+0

No intenté esa combinación de Equals() anteriormente, pero no funciona. Object.RefEquals (obj, DbNull.Value), Object.Equals (obj, DbNull.Value), obj == DBNull.Value y DbNull.Value.Equals (obj) devuelven falso después de la deserialización. – ligos

Cuestiones relacionadas