当我使用 XmlSerialiser 反序列化 DbNull 时,为什么它不是单例?
我一直认为 DbNull.value 是一个单例。 因此,您可以执行如下操作:
VB.NET:C#
If someObject Is DbNull.Value Then
...
End if
:
If (someObject == DbNull.Value)
{
...
}
但是最近,我使用 XmlSerialiser 序列化了 DbNull 实例,突然间它不再是单例了。 不过,类型比较操作(如 C# 的(obj 为 DBNull))工作正常。
代码如下:
[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;
}
为什么会这样呢? 它是如何发生的? 任何其他静态字段也可能发生这种情况吗?
PS:我知道 VB 代码示例正在进行引用比较,而 C# 正在调用 Object.Equals。 两者与 DBNull 具有相同的行为。 我通常使用VB。
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
虽然 DBNull.Value 是静态只读并且仅作为单个实例存在...当您反序列化时,序列化代码将创建该类的新实例来自流中“数据”的
DBNull
。 由于DBNull.Value
只是一个DBNull
实例,因此序列化无法知道它是一个“特殊”实例。注意:
出于同样的原因,如果您使用序列化然后反序列化的“单例”实例创建自己的类,您将获得完全相同的行为。 尽管反序列化的实例与原始实例无法区分,但它们不会是同一个实例。
Although
DBNull.Value
is astatic readonly
and only exists as a single instance... when you de-serialize, the serialization code would be creating a new instance of the classDBNull
from the 'data' in the stream. Since theDBNull.Value
is simply aDBNull
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.
您的 C# 代码不等于调用 .Equals 方法。 没有测试过它,我实际上很确定如果你用它替换
会给
你预期的结果。 有关相等运算符和 Equals 方法的一些内部知识,请查看:
Eric Lipperts 博客文章关于这个主题
Your c# code does not equal calling the .Equals method. With out having tested it Im actually pretty sure if you substituted
with
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