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?
DataContractSerializer can able to serialize types that implements Idictionary whereas XML serializer not. DataContractSerializer serializes all members which are marked with [DataMember] attribute even if member is marked private. XML serializer serialize only public members.
XmlSerializer enables you to control how objects are encoded into XML. The XmlSerializer enables you to control how objects are encoded into XML, it has a number of constructors.
The XmlSerializer creates C# (. cs) files and compiles them into . dll files in the directory named by the TEMP environment variable; serialization occurs with those DLLs. These serialization assemblies can be generated in advance and signed by using the SGen.exe tool.
Since XmlSerializer is one of the few thread safe classes in the framework you really only need a single instance of each serializer even in a multithreaded application.
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...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With