I have several classes that are immutable once their initial values are set. Eric Lippert calls this write-once immutability.
Implementing write-once immutability in C# usually means setting the initial values via the constructor. These values initialize readonly fields.
But if you need to serialize a class like this to XML, using either the XmlSerializer or the DataContractSerializer, you must have a parameterless constructor.
Does anyone have suggestions for how to work around this problem? Are there other forms of immutability that work better with serialization?
EDIT: As #Todd pointed out, the DataContractSerializer does not require a parameterless constructor. According to the DataContractSerializer documentation on MSDN, DataContractSerializer "does not call the constructor of the target object."
Assuming this is your "immutable" object :
public class Immutable
{
public Immutable(string foo, int bar)
{
this.Foo = foo;
this.Bar = bar;
}
public string Foo { get; private set; }
public int Bar { get; private set; }
}
You can create a dummy class to represent that immutable object during serialization/deserialization :
public class DummyImmutable
{
public DummyImmutable(Immutable i)
{
this.Foo = i.Foo;
this.Bar = i.Bar;
}
public string Foo { get; set; }
public int Bar { get; set; }
public Immutable GetImmutable()
{
return new Immutable(this.Foo, this.Bar);
}
}
When you have a property of type Immutable, don't serialize it, and instead serialize a DummyImmutable :
[XmlIgnore]
public Immutable SomeProperty { get; set; }
[XmlElement("SomeProperty")]
public DummyImmutable SomePropertyXml
{
get { return new DummyImmutable(this.SomeProperty); }
set { this.SomeProperty = value != null ? value.GetImmutable() : null; }
}
OK, this is a bit long for something that looks so simple... but it should work ;)
If the class is truly immutable, just use public readonly fields marked with attributes.
[DataContract()]
public class Immutable
{
[DataMember(IsRequired=true)]
public readonly string Member;
public Immutable(string member)
{
Member = member;
}
}
"Realio-trulio" immutability involves the constructor. Popsicle immutability is where you can do, for example:
Person p = new Person();
p.Name = "Fred";
p.DateOfBirth = DateTime.Today;
p.Freeze(); // **now** immutable (edit attempts throw an exception)
(or the same with an object initializer)
This fits DataContractSerializer quite well, as long as you handle to on-serialized callback to do the Freeze. XmlSerializer doesn't do serialization callbacks, so is more work.
Either would suit if you use custom serialization (IXmlSerializable), though. Likewise, custom serialization is broadly doable with realio-trulio immutability, but is painful - and it is a bit of a lie, as it is "create once, then call interface method" - so not really properly immutable.
For true immutability, use a DTO.
I recommend taking a look at the discussion here: Why XML-Serializable class need a parameterless constructor.
You should consider using DataContractSerializer. As far as I can tell from the docs, this do not require a parameterless constructor, and can serialize/deserialize private members.
I just had a look at the article you linked to. In his terminology, objects using readonly fields initialized in the constructor are called "write-only immutability".
"Popsicle immutability" is a bit different. Lippert gives two examples of where it would be useful: deserialization (the problem which you are trying to solve), and circular references where A and B need to be created independently but A needs have a reference to B, and B a reference to A.
The two more obvious ways to achieve this result have been mentioned here (as I was writing this, in fact). The pattern Thomas Levesque mentions is basically the "Builder" pattern. But it's rather unwieldly in this case because you need to not only go from Builder to Immutable, but also from Immutable to Builder so that the serialization/deserialization is symmetrical.
So the "lock" pattern, as mentioned by Marc Gravell, seems more useful. I'm not familiar with C# though, so I'm not sure how best to implement it. I guess probably a private property such as locked. Then all the getter methods need to explicitly check whether the object is locked (aka "frozen") yet. If so they should throw an exception (it's a runtime error; you cannot enforce popstick immutability at compile time).
Related
We have some setup classes in our project, which are serialized / deserialized with XmlSerializer from some .config-Files. In some of those setup classes we have collections of sub-setups like this:
using System;
using System.Collections.ObjectModel;
using System.Xml.Serialization;
namespace Datev.Framework.Shared.Actions.Setup
{
[Serializable]
[XmlSerializerAssembly]
[XmlRoot("setup")]
public class SetupXml
{
public SetupXml()
{
SubSetups = new Collection<SubSetupXml>();
}
[XmlArray("subSetups")]
[XmlArrayItem("subSetup")]
public Collection<SubSetupXml> SubSetups { get; private set; }
}
[Serializable]
public class SubSetupXml
{
[XmlElement("someValue")]
public string SomeValue { get; set; }
}
}
We are using the attribute [XmlSerializerAssembly] to have the best performance for reading and writing the setups.
And here is my problem: We are using Collection to avoid the CA-Warning "Don't use arrays". When we make the setter of SubSetups public, we get the CA-Warning CA2227 "Don't make the setter of a collection public". If we make the setter of the property SubSetups private (like in the code sample), we'll get an error in the generated serializer. The method "GenerateSerializer" (invoked in a tool of us) the code has a line like this:
if (o.SubSetups == null) o.SubSetups = new Collection<SubSetupXml>();
If we make the setter private, we'll get a CS0200 "Property SubSetups cannont be assigned" during building the serializer.
Does anyone know how to make a correct setup with a generated serializer without suppressing a CA-Warning?
It is hard to tell: a "correct" setup depends highly on the context.
Just a quick idea: what happens if you move the logic from "GenerateSerializer" to the property getter? Would it be acceptable?
[XmlArray("subSetups")]
[XmlArrayItem("subSetup")]
public Collection<SubSetupXml> SubSetups {
get {
// subSetups needs to be a backing (private) field... is this a problem?
if (this.subSetups == null) this.subSetups = new Collection<SubSetupXml>();
}
private set;
}
This way, in "GenerateSerializer" you just get the collection. If the collection has not already been created, it will be inside the getter, without needing to create it outside the class.
Just an idea, let me know if it is not applicable.
If the situation is as straightforward as it seems then You don't need to check whether (o.SubSetups == null) because You have the line SubSetups = new Collection<SubSetupXml>(); in the SetupXml() constructor (that is, of course, if o is of type SetupXml). If you get rid of that if statement from the GenerateSerializer method and make the setter private You should be fine - there's no way the SubSetups property can be null unless there are some other ways of messing around with it that You didn't mention...
You could have something like this:
public class SetupXml
{
public SetupXml()
{
SubSetups = new Collection<SubSetupXml>();
}
[XmlIgnore]
public Collection<SubSetupXml> SubSetups { get; private set; }
[EditorBrowsable(EditorBrowsableState.Never)]
[GeneratedCodeAttribute("Whatever", "1.0.0.0")]
[XmlArray("subSetups")]
[XmlArrayItem("subSetup")]
public SubSetupXml[] SerializationSubSetups
{
get
{
return SubSetups.ToArray();
}
get
{
SubSetups = new SubSetups();
if (value != null)
{
foreach(SubSetupXml ssx in value)
{
SubSetups.Add(ssx);
}
}
}
}
}
It's not perfect, but the EditorBrowsable attribute will prevent developers using this library (from another assembly) to see it displayed by intellisense/autocompletion tools. And the GeneratedCode attribute will prevent CA warning on it.
I assume that you have already consulted this article?
http://msdn.microsoft.com/en-us/library/ms182327.aspx
This strikes me as an important note in that article:
"Both binary and XML serialization support read-only properties that are collections. The System.Xml.Serialization.XmlSerializer class has specific requirements for types that implement ICollection and System.Collections.IEnumerable in order to be serializable."
Further to that you may be able to make more progress with the .Clear() and then .AddRange() approach, detailed there.
You can try to implement IXmlSerializable interface. It requires a bit more work but it gives you fine control on the serialization, and in your case access to the private class variables. In ReadXml method you just have to create and instance of your collection, iterate over each node in the source xml and parse the value
Changing the type of SubSetups to IEnumerable will get rid of the code analysis warning, but I can't tell if this is appropriate for you.
[XmlArray("subSetups")]
[XmlArrayItem("subSetup")]
public IEnumerable<SubSetupXml> SubSetups { get; set; }
I have a naming problem for some of my classes. I need to wrap some primitive .net types into a class like the following. There will be about 20 of such classes.
(The naming is crap, of course. Just for a demonstrative purpose)
public class Int32Single
{
public int Value { get; set; }
}
public class Int32Double
{
public int Value1 { get; set; }
public int Value2 { get; set; }
}
public class DoubleSingle
{
public double Value { get; set; }
}
I can't use a generic approach for this.
How should I name such wrapper classes, where each class name should provide the necessary information which primite types are wrapped and in which quantity?
It might also be possible that I have class that contains mixed primite types.
This doesn't seem like a very good idea at all. You have both the Tuple class and a standard array available, that both make more sense in any conceivable use case. However, that doesn't answer your question, so...
The most intuitive name for a wrapper class would follow the convention of {type-name}Wrapper, or for example, Int32Wrapper. In your case, the wrapped object is a primitive type, so makes sense to call the class a "Tuple". Since you want to specify the size of the Tuple in your class name, {primitive-type-name}{size}Tuple seems like the most intuitive naming convention but this causes several problems.
The natural language used to describe Tuples create ambiguity (such as Single and Double because they conflict with the Type names). (e.g. DoubleDouble is bad)
Integers are used in the naming of some primitive types so this could cause ambiguity. (e.g. Int322Tuple is bad).
We can't move the size to the beginning such as 2Int32Tuple because integers are not valid characters to begin a class name. So, There are two approaches that I think could work.
I think your best bet to get around these constraints, is to use a {primitive-type-name}{text-represented-size}Tuple convention. (e.g. Int32TwoTuple or DoubleTwoTuple). This convention expresses the contents of the wrapper class without ambiguity, so it seems like a good approach. In addition the name begins with the primitive type name, so, if you have a lot of these classes, it will be easier for your IntelliSense to fill in the correct class name, and it will alphabetically be listed next to the primitive type that is being wrapped.
Generics can help you out here:
public class WrapTwo<T>
{
public T Value1 { get; set; }
public T Value2 { get; set; }
}
public class WrapOne<T>
{
public T Value1 { get; set; }
}
And have you considered the Tuple class?
OneInt32, TwoInt32s, TwoDoubles? Doesn't sound great.
Tuples? http://www.dotnetperls.com/tuple
I don't very fond of Tuples or arrays, because both don't tell much about their purpose. Well, I use them. But mostly as internal members of classes, local variables, or with 3rd party/legacy code.
Back to naming. Compare:
Tuple<int,int> a = Tuple.Create(10,10);
Int32Double b = new Int32Double(15, 15);
WrapTwo<int> c = new WrapTwo<int>(20, 20);
With
Point a = new Point(10, 10);
Vertex b = new Vertex(15, 15);
One can argue, that 'a' is not good name for variable (and suggest to use 'pointA' instead). But I think it's pretty good in context of geometry application.
Not just type name and creation code looks obscure, but consider type fields names:
a.X = 20;
b.Value1 = 20;
So, I think you need some self-descriptive type in context of your application domain.
I just realized something crazy, which I assumed to be completely impossible : when deserializing an object, the DataContractSerializer doesn't call the constructor !
Take this class, for instance :
[DataContract]
public class Book
{
public Book()
{ // breakpoint here
}
[DataMember(Order = 0)]
public string Title { get; set; }
[DataMember(Order = 1)]
public string Author { get; set; }
[DataMember(Order = 2)]
public string Summary { get; set; }
}
When I deserialize an object of that class, the breakpoint is not hit. I have absolutely no idea how it is possible, since it is the only constructor for this object !
I assumed that perhaps an additional constructor was generated by the compiler because of the DataContract attribute, but I couldn't find it through reflection...
So, what I'd like to know is this : how could an instance of my class be created without the constructor being called ??
NOTE: I know that I can use the OnDeserializing attribute to initialize my object when deserialization begins, this is not the subject of my question.
DataContractSerializer (like BinaryFormatter) doesn't use any constructor. It creates the object as empty memory.
For example:
Type type = typeof(Customer);
object obj = System.Runtime.Serialization.
FormatterServices.GetUninitializedObject(type);
The assumption is that the deserialization process (or callbacks if necessary) will fully initialize it.
There are some scenario's that wouldn’t be possible without this behavior. Think of the following:
1) You have an object that has one constructor that sets the new instance to an "initialized" state. Then some methods are called on that instance, that bring it in a "processed" state. You don’t want to create new objects having the "processed" state, but you still want de serialize / deserialize the instance.
2) You created a class with a private constructor and some static properties to control a small set of allowed constructor parameters. Now you can still serialize / deserialize them.
XmlSerializer has the behavior you expected. I have had a some problems with the XmlSerializer because it DOES need a default constructor. Related to that, sometimes it makes sense to have private property setters. But the XmlSerializer also needs public getter and setter on properties in order to serialize / deserialize.
I think of the DataContractSerializer / BinaryFormatter behavior like suspending the state of an instance during serialization and resuming during deserialization. In other words, the instances are not “constructed” but “restored” to an earlier state.
As you already mentioned, the [OnDeserializing] attribute makes it possible to keep non serialized data in sync.
FWIW, you can call the constructor explicitly from a [OnDeserializing] method:
[OnDeserializing]
public void OnDeserializing(StreamingContext context)
{
this.GetType().GetConstructor(System.Array.Empty<Type>()).Invoke(this, null);
}
Use [OnDeserialized] attribute to initialise your properties.
// This method is called after the object
// is completely deserialized. Use it instead of the
// constructror.
[OnDeserialized]
void OnDeserialized(StreamingContext context)
{
fullName = firstName + " " + lastName;
}
Please refer to microsoft guid-lines:
https://learn.microsoft.com/en-us/dotnet/standard/serialization/serialization-guidelines
In my case, i wanted to create an object to use in a lock-clause. I tried implementing IDeserializationCallback (didn't work because callback only runs after properties have been assigned), [OnDeserialized] (didn't work, same previous reason), and ISerializable (didn't work because the class is decorated with the [DataContractAttribute]).
My workaround was to initialize the field before it's used using Interlocked.CompareExchange. A bit of unnecessary work gets done, but at least now my field gets initialized when a DataContractSerializer creates it.
Interlocked.CompareExchange(ref _sync, new object(), null);
I swear I have seen an example of this but have been googling for a bit and can not find it.
I have a class that has a reference to an object and need to have a GET; method for it. My problem is that I do not want anyone to be able to fiddle with it, i.e. I want them to get a read only version of it, (note I need to be able to alter it from within my class).
Thanks
No, there's no way of doing this. For instance, if you return a List<string> (and it's not immutable) then callers will be able to add entries.
The normal way round this is to return an immutable wrapper, e.g. ReadOnlyCollection<T>.
For other mutable types, you may need to clone the value before returning it.
Note that just returning an immutable interface view (e.g. returning IEnumerable<T> instead of List<T>) won't stop a caller from casting back to the mutable type and mutating.
EDIT: Note that apart from anything else, this kind of concern is one of the reasons why immutable types make it easier to reason about code :)
Return a reference to a stripped-down interface:
interface IFoo
string Bar { get; }
class ClassWithGet
public IFoo GetFoo(...);
If the object isn't too complicated/extensive then write an wrapper around it.
for example:
class A {
public string strField = 'string';
public int intField = 10;
}
class AWrapper {
private A _aObj;
public AWrapper(A aobj) {
_aObj = A;
}
public string strField {
get {
return _aObj.strField;
}
}
public int intField {
get {
return _aObj.intField;
}
}
}
So now all you do is give your client code an instance of the AWrapper class so that they may only use what you allow them to see.
this may get a bit complicated and may not scale well if your base class is not set in stone, but for most simple situation it may just do the trick. I think this is called a facade pattern(but don't quote me on that =) )
This isn't possible. Get and set accessors to reference types get and set the reference to the object. You can prevent changes to the reference by using a private (or internal) setter, but you cannot prevent changes to the object itself if it's exposed by a getter.
Your question reads like you're looking for:
public PropertyName { get; private set; }
But then, given the answers so far I'm not sure I'm interpreting your question correctly. Besides, who am I to question Jon Skeet? :)
i agree with ReadOnlyCollection
See my simple code:
private List<Device> _devices;
public readonly System.Collections.ObjectModel.ReadOnlyCollection<Device> Devices
{
get
{
return (_devices.AsReadOnly());
}
}
ReadOnlyCollection dosen't has Add method so user cant add properties to it.BUT ther is no warranty that if user can modify objects by calling their methods....
I have faced this problem in a certain way.
I have a CategoryViewModel class, which have a property Category that I want private read-only :
public CategoryViewModel
{
private Category { get; }
}
In fact, I want it to be exported as read-only to other class. However I can't do such thing.
In my case (maybe it will help some other guys), I want to add it to a repository. The only way that I've found is to have a function with the repository as param 1, and an Action as param 2 :
public void ApplyAction(ICategoryRepository repo, Action<ICategoryRepository, Category> action)
{
action(repo, Category);
}
Like that, from elsewhere, I can do such thing :
categoryViewModel.ApplyAction(_repository, (r, c) => r.MarkForInsertOrUpdate(c));
This can help other to expose there property only for certains cases and can manage them.
This is one i struggled with for ages so thought I'd document somewhere. (Apologies for asking and answering a question.)
(C# .net 2.0)
I had a class that was being serialized by XmlSerializer, I added a new public property however it wasn't being included in the output XML.
It's not mentioned in the docs anywhere I could find, but public properties must have a set as well as a get to be serialized! I guess this is because it assumes that if you're going to serialize then you'll want to deserialize from the same file, so only serializes properties that have both a set and a get.
As mentioned, most properties must have both a getter and setter; the main exception to this is lists - for example:
private readonly List<Foo> bar = new List<Foo>();
public List<Foo> Bar {get { return bar; } } // works fine
which will work fine; however, if XmlSerializer finds a setter - it demands that it is public; the following will not work:
public List<Foo> Bar {get; private set;} // FAIL
Other reasons it might not serialize:
it isn't public with get and set (or is readonly for a field)
it has a [DefaultValue] attribute, and is with that value
it has a public bool ShouldSerializeFoo() method that returned false
it has a public bool FooSpecified {get;set;} property or field that returned false
it is marked [XmlIgnore]
it is marked [Obsolete]
Any of these will cause it not to serialize
The point about getter+setter is made in the 3rd paragraph on the "Intro to Xml Serialization" page. It's actually in a call-out box. Can't miss it!
Intro-to-XML Serialization http://www.freeimagehosting.net/uploads/2f04fea2db.png
(having a little too much fun with Freeimagehosting.net)
Also properties that return null are not serialized!
if you don't want to implement proper Setters (because maybe you are neither wanting to deserialize or change an objects value) you can just use dummy setters like this set { }, so that the XMLSerializer works, but nothing happens if you use the Setter...
i.E.
public string ID { get { return _item.ID.ToString(); } set { } }
And if your class inherits a list and also has its own members, only the elements of the list get serialized. The data present in your class members is not captured.
Took some time figuring out this!
One more thing to add about serialization of collections:
The XmlSerializer ignores collections of interfaces!
And by that I mean ignore. While you will get an exception for a line like:
public IFoo Foo { get; set; }
you will not get an exception for:
public ICollection<IFoo> LotsOfFoos { get { return this.fooBackingField; } }
You can implement the IXmlSerializer and do the serialization manually, and benefit from serializing properties, and vice versa, deserializing them using constructors / private field assignment.