Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/271.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 仅在反序列化时设置_C#_.net_Serialization_Constructor_Properties - Fatal编程技术网

C# 仅在反序列化时设置

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

问题:

我有一个类,比如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 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
    ),并且容易出错。。。除非你必须这样做,否则不要这样做
  • 使用不同的序列化程序(例如,
    DataContractSerializer
    ,它也支持私有getter/setter或字段,但不支持完整的xml控制)
  • 使用单独的DTO;i、 e.将你的类与应用程序中的私有setter一起使用,并使用单独的(更简单的)类(public get/set)进行序列化,可能在它们之间使用隐式转换运算符
  • 将get/set公开,不要担心
我想我会选择DTO选项;它保留了对xml的简单但完整的格式控制,并且不需要做很多工作

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直观

在这种情况下,您可能需要尝试以下技巧作为解决方法:)

  • 使Foo.Id属性为只读
  • 创建一个容器对象Boo。Boo只包含要序列化的相同类型的成员变量。在本例中,Boo将具有带有publicsetter和getter的Id属性。Boo不应包括Foo拥有的任何成员方法
  • 使用Boo进行xml序列化和反序列化,使用Foo处理业务逻辑。逻辑
  • 请参见下面的示例代码:

    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?
        }
    }