使用Serializable属性和实现ISerializable接口有什么区别?
看起来我可以序列化没有该接口的类,所以我不清楚它的用途.
我试图序列化/反序列化包含a的对象Dictionary<Tuid,Section>.这些都是自定义类型.
在我的代码中,我有一种模板,其中包含Dictionary<Tuid,Section>.我试图序列化/反序列化的是Template类.
要解决此集合是字典的问题,我已ISerializable在Template类上实现了接口....
[Serializable]
public class Template : ISerializable
{
protected Template(SerializationInfo info, StreamingContext context)
{
// Deserialize the sections
List<Tuid> tuids = (List<Tuid>)info.GetValue("Sections_Keys", typeof(List<Tuid>));
List<Section> sections = (List<Section>)info.GetValue("Sections_Values", typeof(List<Section>));
this._sections = new Dictionary<Tuid, Section>();
for (int i = 0; i < tuids.Count; i++)
{
_sections.Add(tuids[i], sections[i]);
}
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
List<Tuid> tuids = new List<Tuid>();
List<Section> sections = new List<Section>();
foreach (KeyValuePair<Tuid, Section> kvp …Run Code Online (Sandbox Code Playgroud) 我有一个带有子类的自定义抽象基类,我已经使用ISerializable进行了可序列化/可序列化.当我对这个类的子类的单个实例进行序列化/反序列化时,一切正常.但是,当我做一个数组时,我总是在反序列化时得到一个空数组.使用BinaryFormatter完成序列化.
这些项目包含在:
public ObservableCollection<Trade> Trades { get; private set; }
Run Code Online (Sandbox Code Playgroud)
在序列化时,这是在SerializationInfo参数的GetObjectData中完成的:
Trade[] trades = (Trade[])Trades.ToArray<Trade>();
info.AddValue("trades", trades);
Run Code Online (Sandbox Code Playgroud)
在反序列化时,这也是在SerializationInfo参数的序列化构造函数中完成的:
Trade[] trades = (Trade[])info.GetValue("trades", typeof(Trade[]));
foreach (Trade t in trades)
{
Trades.Add(t);
}
Run Code Online (Sandbox Code Playgroud)
反序列化总是给我一个空数组,正如我前面提到的,单个项目序列化和deseriaizes与这段代码很好:
序列化(GetObjectData方法):
info.AddValue("trade", Trades.First<Trade>());
Run Code Online (Sandbox Code Playgroud)
反序列化(序列化构造函数):
Trade t = (Trade)info.GetValue("trade", typeof(Trade));
Trades.Add(t);
Run Code Online (Sandbox Code Playgroud)
这是个常见的问题吗?我似乎发现至少没有其他任何人参与其中.希望有一个解决方案:)如果我需要为您提供更多信息/代码,请告诉我.
谢谢!
这个问题接近我感兴趣的问题,但并不完全.
我有一个用C#编写的.NET WinForms应用程序.我有一个ListView显示C#对象数组的控件.我已将它连接起来,以便您可以将这些listview项拖放到同一应用程序中的不同表单,并将对象数组(类型Session)正确传递给该另一个表单的drop handler.
但是,我现在想要支持跨进程拖放,我运行应用程序的多个实例.这看起来它将起作用(例如GetDataPresent成功),但最终在我实际尝试检索数据时抛出异常 - 无法转换object[]为Session[].
if (e.Data.GetDataPresent("Fiddler.Session[]"))
{
Session[] oDroppedSessions;
try
{
oDroppedSessions = (Session[])e.Data.GetData("Fiddler.Session[]");
}
catch (Exception eX)
{ // reaches here
}
}
Run Code Online (Sandbox Code Playgroud)
任何人都知道我是否必须ISerializable为我的对象实现才能使其工作?通常情况下,我只是尝试一下,但实现ISerializable这个课程将是非常重要的,我担心这样做可能会产生奇怪的副作用.
更新:实现ISerializable没有帮助 - 永远不会调用该方法.同样,将Serializable属性添加到类中也没有任何影响.还有其他想法吗?
我必须使用一个旧的应用程序,它使用binaryFormatter将应用程序数据序列化到文件流中(例如在一个名为"data.oldformat"的文件中),而没有任何优化主类已经标记了属性
<serializable()>public MainClass
.......
end class
Run Code Online (Sandbox Code Playgroud)
和序列化代码
dim b as new binaryformatter
b.serialize(mystream,mymainclass)
Run Code Online (Sandbox Code Playgroud)
为了优化序列化/反序列化过程,我简单地使类实现了ISerializable接口并编写了一些优化的序列化例程
<serializable()>public MainClass
implements ISerializable
.......
end class
Run Code Online (Sandbox Code Playgroud)
优化工作非常好但我必须找到一种方法来恢复旧文件中的数据以实现向后兼容.
我怎样才能做到这一点??
皮耶路易吉
对于以下异常实现,SonarCube 显示错误“更新‘ISerializable’的这个实现以符合推荐的序列化模式”:
[Serializable]
public class UnrecoverableException : Exception, ISerializable
{
public bool Ignore { get; }
public UnrecoverableException()
{
}
public UnrecoverableException(string message, Exception innerException)
: base(message, innerException)
{
}
protected UnrecoverableException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
Ignore= info.GetBoolean(nameof(Ignore));
}
public UnrecoverableException(string message, bool ignore= false) : base(message)
{
Ignore= ignore;
}
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue(nameof(Ignore), Ignore);
base.GetObjectData(info, context);
}
}
Run Code Online (Sandbox Code Playgroud)
不知道这里有什么问题对我来说似乎完全遵循这里描述的规则https://rules.sonarsource.com/csharp/tag/pitfall/RSPEC-3925
此规则在
ISerializable不遵循 Microsoft 推荐的序列化模式的情况下实现的类型会引发问题。
System.SerializableAttribute缺少该属性。不可序列化的字段没有用该 …
我有一个数据访问层,一个服务层和一个表示层.表示层是ASP.NET MVC2 RTM(Web),服务层是WCF(服务).这都是.NET 3.5 SP1.
问题是在服务中,返回的对象用[DataContract]属性标记.Web正在使用AppFabric Cache(aka Velocity)SessionStateProvider来存储会话状态.因此,我在会话中存储的任何内容都必须是可序列化的.
问题就出现了:DataContracts没有标记,[Serializable]并且据我所知,通过将它引入已经标记出[DataContract]某些问题的类,因此我不相信这是一个解决方案.
我最初计划在Web层使用DataContracts,将它们用作与渲染DataContracts相关的视图的模型(可能嵌套在更高级别的ViewModel类中).但是由于会话状态提供程序要求存储在其中的所有对象都是可序列化的,所以我开始重新考虑这种策略.尽管如此,它会很好,因为它们包含使用IDataErrorInfo接口的验证逻辑,并且相同的验证逻辑可以作为模型绑定的一部分在MVC中重用.
您认为什么是让我减少所需工作的最佳方式?
我目前想到了以下不同的方式:
A.在Web项目中创建"ServiceIntegration"部分.
这将是我的控制器和我的WCF服务层之间的中间人.ServiceIntegration部分将使用DataContracts与服务层对话,使用ViewModels与Web层对话,但必须使用双向Transformer在DataContracts和ViewModel之间进行转换.
此外,由于IDataErrorInfo验证不可重复使用,因此有必要为每个DataContract创建一个Validator,它使用Transformer从ViewModel转换为DataContract,使用IDataErrorInfo执行验证并返回其结果.然后将在控制器的动作方法中使用(例如if (!MyValidator.IsValid(viewModel)) return View();)
需要不同的类:xDataContract,xViewModel,xTransformer,xValidator
B.在Web项目中创建"SessionIntegration"部分
这将是控制器(或访问会话的任何内容)和会话本身之间的中间人.任何需要访问会话的内容都将通过此课程.DataContracts将在整个应用程序中使用,除非它们存储在会话中.SessionIntegration部分负责将DataContract转换为某种ISerializable形式,然后返回.由于在DataContract上使用了IDataErrorInfo接口,因此无需额外的Validator.
需要不同的类:xDataContract,xTransformer,xSerializableForm
注意:在两种情况下仍然会有ViewModels,但是(B)我可以从DataContracts组成ViewModels.
(B)具有不需要额外验证器的好处.
在我完全实现(A)/(B)之前,我想要一些反馈.目前,我开始倾向于(B),但是,(A)可能更灵活.无论哪种方式,对于它的价值而言似乎太过分了.有没有其他人遇到过这个问题,你是否同意/不同意我,和/或你有其他办法解决这个问题吗?
谢谢,
詹姆士
asp.net-mvc session datacontract iserializable session-state-provider
我有一种情况,我使用NetDataContractSerializer序列化一些.NET对象,并将XML存储在数据库中,以此来记住应用程序中这些对象的状态.最近我遇到了第一种情况,其中一些代码重构属性和类型名称导致无法反序列化此XML数据.
到目前为止,我已经提出了两种不同的攻击计划,用于处理版本兼容性中断,例如使用NetDataContractSerializer本身可用的工具来控制反序列化或直接转换XML.从我的实验和研究看来,可以使用自定义SerializationBinder将其反序列化为不同的类型,并且可以通过实现ISerializable或通过实现ISurrogateSelector和ISerializationSurrogate来编写序列化代理来解决属性名称/类型更改.不幸的是,这个首选机制还没有完成,除非我可以显示,否则看起来使用代理商在NetDataContractSerializer上无法在序列化数据的版本之间移动,这是由于微软的一些无法解释的设计决定.Microsoft提出的建议是在双方使用相同的序列化,这完全违背了使用代理的目的,以便在类型名称更改或移动到不同的命名空间或程序集中时提供帮助.
要修复它,请使用相同的NetDataContractSerializer实例或另一个也使用兼容的SurrogateSelector初始化的实例.
这个解释与MSDN文章冲突,该文章说明了如何使用自定义绑定器替换类型以及处理序列化结构中的其他更改.
在反序列化期间,格式化程序看到已设置了活页夹.当每个对象即将被反序列化时,格式化程序调用绑定器的BindToType方法,向其传递格式化程序要反序列化的程序集名称和类型.此时,BindToType决定实际构造的类型并返回此类型.
请注意,如果新类型通过Serializable自定义属性使用简单序列化,则原始类型和新类型必须具有相同的确切字段名称和类型.但是,该类型的新版本可以实现ISerializable接口,然后将调用其特殊构造函数,该类型可以检查SerializationInfo对象中的值并确定如何反序列化自身.
因此,要么我能够让NetDataContractSerializer将我的V1 XML反序列化为我的V2类型,要么我将不得不手动转换XML.如果有人能够证明NetDataContractSerializer的SerializationInfo确实在使用ISerializable或使用序列化代理时确实有效,或者至少提供比Microsoft给出的更好的解释,否则我可能会发布一个新问题来讨论最好的方法在.NET中直接转换旧的XML.
更新2011-08-16: 经过一些实验,似乎ISerializable和序列化代理技术都可以正常工作,如果序列化的原始类型实现ISerializable,否则如果类型只使用[Serializable]属性,它会出现在对象中的每个字段图形以额外属性的形式缺少一些有价值的类型信息.
使用[Serializable]属性的示例
<OldClass2 xmlns:i="http://www.w3.org/2001/XMLSchema-instance" z:Id="1" z:Type="NdcsSurrogateTest.OldClass2" z:Assembly="NdcsSurrogateTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" xmlns="http://schemas.datacontract.org/2004/07/NdcsSurrogateTest">
<_stable z:Id="2">Remains the same</_stable>
<_x003C_OldProperty_x003E_k__BackingField>23</_x003C_OldProperty_x003E_k__BackingField>
</OldClass2>
Run Code Online (Sandbox Code Playgroud)
实现ISerialzable的示例:
<OldClass2 xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:x="http://www.w3.org/2001/XMLSchema" z:Id="1" z:Type="NdcsSurrogateTest.OldClass2" z:Assembly="NdcsSurrogateTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" xmlns="http://schemas.datacontract.org/2004/07/NdcsSurrogateTest">
<_stable z:Id="2" z:Type="System.String" z:Assembly="0" xmlns="">Remains the same</_stable>
<_x003C_OldProperty_x003E_k__BackingField z:Id="3" z:Type="System.Int32" z:Assembly="0" xmlns="">23</_x003C_OldProperty_x003E_k__BackingField>
</OldClass2>
Run Code Online (Sandbox Code Playgroud)
当使用带有自定义绑定器的NetDataContractSerializer反序列化第一个示例以更改类型,然后在该类型上实现ISerializable或提供指定基本上满足ISerializalbe角色的序列化代理的代理选择器时,您将在ISerializationSurrogate中看到一个空的SerializationInfo .SetObjectData方法.在第二个示例中处理xml时,SerializationInfo似乎可以获得正确的信息,并且按预期工作.
我的结论是NetDataContractSerializer为仅支持通过SerializableAttribute进行序列化的类型生成的默认XML与使用ISerializable或序列化代理技术的反序列化不兼容,因为缺少类型信息.因此,为了使NetDataContractSerializable更具未来性,可以自定义序列化以确保XML中包含此类型信息,以便可以自定义以后的反序列化,而无需手动转换源XML.
我不明白它是如何工作的:当我实现 ISerializable 接口时,我必须定义 protected(除非类是密封的,在这种情况下,构造函数应该标记为私有)构造函数:
protected MyClass(SerializationInfo info, StreamingContext context)
此访问修饰符使此构造函数无法用于那么项目如何反序列化成功呢?
iserializable ×10
c# ×7
.net ×3
arrays ×1
asp.net-mvc ×1
attributes ×1
constructor ×1
datacontract ×1
inheritance ×1
serializable ×1
session ×1
sonarqube ×1
winforms ×1