Field Initializer in C# Class Not Run When Deserializing

Field Initializer in C# Class not Run when Deserializing

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

Initialize private readonly fields after Deserializing

Any field declared as private readonly can be instantiated in the same line where it was declared or inside a constructor. Once that is done it cannot be changed.

From MSDN:

The readonly keyword is a modifier that you can use on fields. When a field declaration includes a readonly modifier, assignments to the fields introduced by the declaration can only occur as part of the declaration or in a constructor in the same class.

That means that you will have to remove readonly keyword to get it to work.

Auto-Property Initializers not filled

The auto-property initializer in C# 6.0 is syntactic sugar and the compiler will create a backing field for the property that is initialized to the given expression.

Therefore, your code is equivalent to the following declaration (I added a class ´SampleClass` for clarification):

class SampleClass
{
// compiler-generated backing field initialized by the field initializer
private readonly SampleEnum __sampleProp1 = SampleEnum.Value1;

public SampleEnum SampleProp1 { get { return __sampleProp1; } }

public SampleEnum SampleProp2 { get { return SampleEnum.Value1; } }
}

Your problem comes from the fact that the deserializer used by WCF does not execute the field initializers.

A possible solution would be to make use of the OnDeserializing or OnDerserialized attributes and place all your initialization code into a separate method (as described in this question: Field Initializer in C# Class not Run when Deserializing).

Constructors Not Called On Deserialization

You're deserializing the json2 string.

var json2 =

@"{

""Val1"":""hello""

}";

I don't believe the constructor is being called, but the 'hello' is being assigned by the JSON string.

Can a readonly field be initialized when using DataContractSerializer?

I'm not sure doing this is a good idea, but you can change the value of a readonly field outside the constructor or field initializer by using reflection.

Putting something like:

typeof(MyType).GetField("Field").SetValue(this, value);

in your deserialization callback should work.

c# [NonSerialized] field with inline initialization isn't initialized after deserialization

You could set it in the default constructor.

Implement the System.Runtime.Serialization.IDeserializationCallback

It is called afther the object is deserialized so you can perform your extra initialization there .

Why C# won't allow field initializer with non-static fields?

I'm more interested with the reason/logic for why it was restricted. just for curiosity.

If you read the C# Language Spec, 10.11.3, it hints as to the rationale here. In discussing variable initializers:

It is useful to think of instance variable initializers and constructor initializers as statements that are automatically inserted before the constructor-body.

Since these are "inserted before the constructor", they are being executed prior to this being valid, so allowing you to refer to other members (effectively this) would be problematic.

Note that this is consistent with how static fields work, as well. In both cases, you are allowed to access static data, but not instance data. The error message you receive ("A field initializer cannot reference the non-static field, method, or property") directly notes this.

When is the class constructor called while deserialising using XmlSerializer.Deserialize?

No it is not OK to assume the properties will be set when the constructor runs. The opposite is true. The constructor is the very first piece of code which runs when an instance of an object is created. It's not possible for the properties to be set until after the constructor has started executing.

The XML deserialization process roughly looks like the following

  • Call the parameterless constructor
  • Set the properties to their deserialized values

A way to work around this is to use a factory method to do the deserialization and then run the logic which depends on the properties being set. For example

class MyClass {
...
public static MyClass Deserialize(string xmlContents) {
var local = ... // Do the XML deserialization
local.PostCreateLogic();
return local;
}
}

error while calling function from another class: A field initializer cannot reference the non static field,method,or property

you should call getSerialNumberFromDriveLetter method inside constructor or create a new method

      public Form1()
{
InitializeComponent();
USBDriveSerialNumber usb = new USBDriveSerialNumber();
string serial = usb.getSerialNumberFromDriveLetter("f:\\");
}


Related Topics



Leave a reply



Submit