C# 仅在反序列化时设置
问题: 我有一个类,比如Foo,它实现了一个Id属性。福一定是 可序列化。应该在初始化时将Foo.Id初始化为新的GUID 福的。设置Foo.Id后,它不应更改。反序列化将尝试设置Foo.Id,因此必须将其公开C# 仅在反序列化时设置,c#,.net,serialization,constructor,properties,C#,.net,Serialization,Constructor,Properties,问题: 我有一个类,比如Foo,它实现了一个Id属性。福一定是 可序列化。应该在初始化时将Foo.Id初始化为新的GUID 福的。设置Foo.Id后,它不应更改。反序列化将尝试设置Foo.Id,因此必须将其公开 Private _Id As String=system.Guid.NewGuid.tostring Public Property Id As String Get return _Id End Get Set(ByVal value As St
Private _Id As String=system.Guid.NewGuid.tostring
Public Property Id As String
Get
return _Id
End Get
Set(ByVal value As String)
_Id = value
End Set
End Property
或者对于c#ers
解决方案思路:
唯一的解决方案似乎是在设置Foo.Id时抛出运行时异常,但是
这将在反序列化过程中导致问题。所以,无论如何,我们必须
确保只有在尝试设置Foo.Id时才会引发异常
在序列化程序外部创建。构造函数中的某种标志或东西
编辑、反序列化方法…
public static Foo DeserializeFromFile(string sFilespec)
{
Xml.Serialization.XmlSerializer oSerializer = new Xml.Serialization.XmlSerializer(typeof(Foo));
System.IO.FileStream oStream = new System.IO.FileStream(sFilespec, IO.FileMode.Open);
Foo oObject = oSerializer.Deserialize(oStream);
oStream.Close();
return oObject;
}
我不确定是否理解您的问题,但您可以尝试在类中实现接口,以手动微调序列化/反序列化过程
[Serializable]
public class YourClass : ISerializable
{
private Guid _Id = Guid.NewGuid();
public string Id
{
get { return _Id; }
private set { _Id = value; }
}
public YourClass() // Normal constructor
{
// ...
}
// This constructor is for deserialization only
private YourClass(SerializationInfo information, StreamingContext context)
{
Id = (Guid)information.GetValue("Id", typeof(Guid)); // etc
}
void ISerializable.GetObjectData(SerializationInfo information,
StreamingContext context)
{
// You serialize stuff like this
information.AddValue("Id", Id, typeof(Guid));
}
}
另外,请阅读该类,了解有关序列化和反序列化最常见类型的更多信息。首先,我认为您的代码无法编译。你需要投到(Foo)。您还缺少一个“使用”块:
更重要的是,除非您实现IXmlSerializable接口并进行自己的反序列化,否则您在这里就不走运了。反序列化Id属性时,可以直接设置_Id字段,而不使用该属性。根据描述,我假设您使用的是
XmlSerializer
。事实上,XmlSerializer
缺少这方面的粒度。它不支持回调(这将允许您检测序列化),等等
选项:
- 实现
——大量工作(使用IXmlSerializable
/XmlReader
),并且容易出错。。。除非你必须这样做,否则不要这样做XmlWriter
- 使用不同的序列化程序(例如,
,它也支持私有getter/setter或字段,但不支持完整的xml控制)DataContractSerializer
- 使用单独的DTO;i、 e.将你的类与应用程序中的私有setter一起使用,并使用单独的(更简单的)类(public get/set)进行序列化,可能在它们之间使用隐式转换运算符
- 将get/set公开,不要担心
using System;
using System.Xml.Serialization;
[XmlType("foo"), XmlRoot("foo")]
public class FooDto {
[XmlAttribute("bar")]
public string Bar { get; set; }
public static implicit operator Foo(FooDto value) {
return value == null ? null :
new Foo(value.Bar);
}
public static implicit operator FooDto(Foo value) {
return value == null ? null :
new FooDto { Bar = value.Bar };
}
}
public class Foo {
private readonly string bar;
public Foo(string bar) { this.bar = bar; }
public string Bar { get { return bar; } }
}
static class Program {
static void Main() {
Foo foo = new Foo("abcdefg");
FooDto dto = foo;
new XmlSerializer(dto.GetType()).Serialize(
Console.Out, dto);
}
}
Jokepu博士所描述的方式似乎是正确的做法。类似地,如果出于任何原因/约束/要求必须使用XmlSerialization,则应该实现IXmlSerializable接口。但是,实现IXmlSerializable可能不如实现ISerializable直观 在这种情况下,您可能需要尝试以下技巧作为解决方法:)
using System;
using System.IO;
using System.Xml.Serialization;
namespace SerializationSample
{
class Program
{
private const string STR_CtempSerilizationxml = @"c:\temp\Serilization.xml";
static void Main(string[] args)
{
Foo foo = new Foo(Guid.NewGuid().ToString());
Console.WriteLine("Foo.Id = " + foo.Id);
SerializeToFile(foo, STR_CtempSerilizationxml);
Foo fooDeserialized = DeserializeFromFile(STR_CtempSerilizationxml);
Console.WriteLine("Foo.Id = " + fooDeserialized.Id);
}
private static void SerializeToFile(Foo foo, string sFilespec)
{
XmlSerializer iSerializer = new XmlSerializer(typeof(Boo));
using (FileStream stream = new FileStream(sFilespec, FileMode.Create))
{
iSerializer.Serialize(stream, new Boo(foo));
}
}
public static Foo DeserializeFromFile(string sFilespec)
{
XmlSerializer oSerializer = new XmlSerializer(typeof(Boo));
using (System.IO.FileStream oStream = new FileStream(sFilespec, FileMode.Open))
{
return new Foo(((Boo)oSerializer.Deserialize(oStream)).Id);
}
}
}
public class Foo
{
private readonly string _Id;
public string Id
{
get { return _Id; }
}
public Foo(string id) { _Id = id; }
}
public class Boo
{
public string Id { get; set; }
public Boo(Foo foo) { Id = foo.Id; }
public Boo() { }
}
}
如果只能设置一次,您可以添加一个bool
private string _Id = system.Guid.NewGuid().ToString();
private bool _IdSet = false;
public string Id {
get { return _Id; }
set
{
if(!_IdSet)
{
_Id = value;
_IdSet = true;
}
// else throw exception?
}
}
您使用的是哪种序列化,以及.net的哪个版本?从OP所讨论的是属性(而不是字段)这一事实来看,我假设他们所讨论的是XmlSerializer。我认为这个答案没有帮助。@Marc Gravel:是的,看起来你是对的。在我的辩护中,当我发布答案时,他谈论的是XmlSerializer这一事实并不明显,他只是在稍后进行了编辑。哈哈。。你比我早11分钟发布:)在我编辑答案和测试样本时不知道你已经发布了。真是个惊喜!!你赢了,马克:)
using System;
using System.IO;
using System.Xml.Serialization;
namespace SerializationSample
{
class Program
{
private const string STR_CtempSerilizationxml = @"c:\temp\Serilization.xml";
static void Main(string[] args)
{
Foo foo = new Foo(Guid.NewGuid().ToString());
Console.WriteLine("Foo.Id = " + foo.Id);
SerializeToFile(foo, STR_CtempSerilizationxml);
Foo fooDeserialized = DeserializeFromFile(STR_CtempSerilizationxml);
Console.WriteLine("Foo.Id = " + fooDeserialized.Id);
}
private static void SerializeToFile(Foo foo, string sFilespec)
{
XmlSerializer iSerializer = new XmlSerializer(typeof(Boo));
using (FileStream stream = new FileStream(sFilespec, FileMode.Create))
{
iSerializer.Serialize(stream, new Boo(foo));
}
}
public static Foo DeserializeFromFile(string sFilespec)
{
XmlSerializer oSerializer = new XmlSerializer(typeof(Boo));
using (System.IO.FileStream oStream = new FileStream(sFilespec, FileMode.Open))
{
return new Foo(((Boo)oSerializer.Deserialize(oStream)).Id);
}
}
}
public class Foo
{
private readonly string _Id;
public string Id
{
get { return _Id; }
}
public Foo(string id) { _Id = id; }
}
public class Boo
{
public string Id { get; set; }
public Boo(Foo foo) { Id = foo.Id; }
public Boo() { }
}
}
private string _Id = system.Guid.NewGuid().ToString();
private bool _IdSet = false;
public string Id {
get { return _Id; }
set
{
if(!_IdSet)
{
_Id = value;
_IdSet = true;
}
// else throw exception?
}
}