字段初始在C#类反序列化时不运行 [英] Field Initializer in C# Class not Run when Deserializing

查看:136
本文介绍了字段初始在C#类反序列化时不运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个类定义了一个受保护的领域。受保护的字段有一个字段初始值。

当我反序列化的具体类,字段的初始化中运行。为什么?这是解决问题的最好模式?如果我移动到初始化一个构造函数,构造函数也没有被调用。

  [DataContract]
公共类MyConcrete
{
    //字段初始不运行时评论说:
    保护只读字典< INT,串> myDict; // =新词典< INT,串>();    公共MyConcrete()
    {
        myDict =新词典< INT,串>();
    }    私人布尔的MyMethod(INT键)
    {
        返回myDict.ContainsKey(键);
    }    私人诠释myProp;    [数据成员]
    公众诠释MyProp
    {
        {返回myProp; }
        集合{布尔B =的MyMethod(值); myProp =价值; } //调用的MyMethod挑起错误
    }
}

原始类层次

  [DataContract]
公共抽象类MyAbstract
{
    //这个初始化程序不可运行,而反序列化:
    保护只读字典< INT,串> myDict =新词典< INT,串>();    私人布尔的MyMethod(INT键)
    {
        返回myDict.ContainsKey(键);
    }    私人诠释myProp;    [数据成员]
    公众诠释MyProp
    {
        {返回myProp; }
        集合{布尔B =的MyMethod(值); myProp =价值; } //调用的MyMethod挑起错误
    }
}[DataContract]
公共类MyConcrete:MyAbstract
{}类节目
{
    静态无效的主要(字串[] args)
    {
        字符串tempfn = Path.GetTempFileName();        MyConcrete混凝土=新MyConcrete(){MyProp = 42};
        字符串数据= concrete.SerializeToString< MyConcrete>();        MyConcrete水化= SerializationHelper.DeserializeFromString&所述; MyConcrete>(数据);
    }
}

护方法

 的静态公共字符串SerializeToString< T>(这件T OBJ)
{
    返回SerializationHelper.SerializeToString< T>(OBJ);
}静态公共字符串SerializeToString< T>(T OBJ)
{
    DataContractSerializer的S =新的DataContractSerializer(typeof运算(T));
    使用(MemoryStream的毫秒=新的MemoryStream())
    {
        s.WriteObject(MS,OBJ);
        ms.Position = 0;
        使用(StreamReader的SR =新的StreamReader(MS))
        {
            串序列= sr.ReadToEnd();
            返回序列化;
        }
    }
}静态公共ŧDeserializeFromString< T>(串serializedDataAsString)
{
    DataContractSerializer的S =新的DataContractSerializer(typeof运算(T));
    使用(MemoryStream的毫秒=新的MemoryStream(Encoding.UTF8.GetBytes(serializedDataAsString)))
    {
        对象S2 = s.ReadObject(毫秒);
        回报(T)S2;
    }
}


解决方案

在反序列化无论是构造或实地初始化被称为和空白未初始化的对象来代替。

要解决它,你可以利用的<一个href=\"http://msdn.microsoft.com/en-us/library/system.runtime.serialization.ondeserializingattribute.aspx\"><$c$c>OnDeserializing或<一个href=\"http://msdn.microsoft.com/en-us/library/system.runtime.serialization.ondeserializedattribute.aspx\"><$c$c>OnDerserialized属性有解串器调用具有以下签名的函数:

 无效OnDeserializing(System.Runtime.Serialization.StreamingContext C);

在该功能中,您可以初始化无论是在反序列化过程中错过了。

在公约的规定,我倾向于有我的构造函数中调用的方法 OnCreated(),然后也有deserializating方法调用同样的事情。然后,您可以处理所有的字段初始化的在那里,并确保它的反序列化前被解雇了。

  [DataContract]
公共抽象类MyAbstract
{
    保护只读字典&LT; INT,串&GT; myDict;    保护MyAbstract()
    {
        OnCreated();
    }    私人无效OnCreated()
    {
        myDict =新词典&LT; INT,串&GT;();
    }    [OnDeserializing]
    私人无效OnDeserializing(的StreamingContext C)
    {
        OnCreated();
    }    私人布尔的MyMethod(INT键)
    {
        返回myDict.ContainsKey(键);
    }    私人诠释myProp;    [数据成员]
    公众诠释MyProp
    {
        {返回myProp; }
        集合{布尔B =的MyMethod(值); myProp =价值; }
    }
}

I have a class that defines a protected field. The protected field has a field initializer.

When I deserialize the concrete class, the field initializer is not run. Why? What is the best pattern to solve the problem? If I move the initialization into a constructor, the constructor is also not invoked.

[DataContract]
public class MyConcrete
{
    // FIELD INITIALIZER DOES NOT RUN WHEN COMMENTED IN:
    protected readonly Dictionary<int, string> myDict;// = new Dictionary<int, string>();

    public MyConcrete()
    {
        myDict = new Dictionary<int, string>();
    }

    private bool MyMethod(int key)
    {
        return myDict.ContainsKey(key);
    }

    private int myProp;

    [DataMember]
    public int MyProp
    {
        get { return myProp; }
        set { bool b = MyMethod(value); myProp = value; } // Call MyMethod to provoke error
    }
}

ORIGINAL CLASS HIERARCHY

[DataContract]
public abstract class MyAbstract
{
    // THIS INITIALIZER IS NOT RUN WHILE DESERIALIZING:
    protected readonly Dictionary<int, string> myDict = new Dictionary<int, string>();

    private bool MyMethod(int key)
    {
        return myDict.ContainsKey(key);
    }

    private int myProp;

    [DataMember]
    public int MyProp
    {
        get { return myProp; }
        set { bool b = MyMethod(value); myProp = value; } // Call MyMethod to provoke error
    }
}

[DataContract]
public class MyConcrete : MyAbstract
{

}

class Program
{
    static void Main(string[] args)
    {
        string tempfn = Path.GetTempFileName();

        MyConcrete concrete = new MyConcrete() { MyProp = 42 };
        string data = concrete.SerializeToString<MyConcrete>();

        MyConcrete rehydrated = SerializationHelper.DeserializeFromString<MyConcrete>(data);
    }
}

SUPPORTING METHODS

static public string SerializeToString<T>(this T obj)
{
    return SerializationHelper.SerializeToString<T>(obj);
}

static public string SerializeToString<T>(T obj)
{
    DataContractSerializer s = new DataContractSerializer(typeof(T));
    using (MemoryStream ms = new MemoryStream())
    {
        s.WriteObject(ms, obj);
        ms.Position = 0;
        using (StreamReader sr = new StreamReader(ms))
        {
            string serialized = sr.ReadToEnd();
            return serialized;
        }
    }            
}

static public T DeserializeFromString<T>(string serializedDataAsString)
{
    DataContractSerializer s = new DataContractSerializer(typeof(T));
    using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(serializedDataAsString)))
    {
        object s2 = s.ReadObject(ms);
        return (T)s2;
    }
}

解决方案

On deserialization neither the constructors nor the field initializers are called and a "blank" un-initialized object is used instead.

To resolve it you can make use of the OnDeserializing or OnDerserialized attributes to have the deserializer call a function with the following signature:

void OnDeserializing(System.Runtime.Serialization.StreamingContext c);

In that function is where you can initialize whatever was missed within the deserialization process.

In terms of convention, I tend to have my constructor call a method OnCreated() and then also have deserializating method call the same thing. You can then handle all of the field initialization in there and be sure it's fired before deserialization.

[DataContract]
public abstract class MyAbstract
{
    protected readonly Dictionary<int, string> myDict;

    protected MyAbstract()
    {
        OnCreated();
    }

    private void OnCreated()
    {
        myDict = new Dictionary<int, string>();
    }

    [OnDeserializing]
    private void OnDeserializing(StreamingContext c)
    {
        OnCreated();
    }

    private bool MyMethod(int key)
    {
        return myDict.ContainsKey(key);
    }

    private int myProp;

    [DataMember]
    public int MyProp
    {
        get { return myProp; }
        set { bool b = MyMethod(value); myProp = value; }
    }
}

这篇关于字段初始在C#类反序列化时不运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆