C# deserializing nested elements with only one item - c#

I use C# to deserialize a XML file. My XML file has the format:
<Produced_by >
<Producing_Unit>
<Unit ID="" Name=""/>
</Producing_Unit>
</Produced_by>
When deserializing I want to remove the middleman Producing_Unit. Since Produced_by will always contain only one subelement Producing_Unit specifying the Unit.
My initial thoughts on how to implement doesn't work:
public class Unit
{
public string Name { get; set; }
public string ID { get; set; }
}
public class Produced_by
{
[XmlElement("Producing_Unit")]
[XmlElement("Unit")]
public Unit Unit { get; set; }
}
It could be soleved by using [XmlArray("Producing_Unit"), XmlArrayItem("Unit")]
and then having Produced_by contain: public List<Unit> {get;set;}. But that's not what I want.

As far as I know, it's not possible to use the XML with the "Producing_Unit" tag but ditch the matching Producing_Unit class with the standard attributes short of implementing the IXmlSerializable interface. Your best bet would be to separate your application/business logic from your serialization layer.
Keep your serialization data model simple and matching your XML schema (this means including the wrapping Producing_Unit class), then simply convert to/from that data model and a cleaner data model (without Producing_Unit) for the rest of your application to work with.
EDIT: Here's an implementation using the IXmlSerializable interface. I just whipped it off and honestly, don't know if it will work for all cases.
public class Unit
{
public string Name { get; set; }
public string ID { get; set; }
}
public class Produced_by : IXmlSerializable
{
public Unit Unit { get; set; }
public void WriteXml (XmlWriter writer)
{
writer.WriteStartElement("Produced_by");
writer.WriteStartElement("Producing_Unit");
writer.WriteStartElement("Unit");
writer.WriteAttributeString("ID", this.Unit.ID);
writer.WriteAttributeString("Name", this.Unit.Name);
writer.WriteEndElement();
writer.WriteEndElement();
writer.WriteEndElement();
}
public void ReadXml (XmlReader reader)
{
while (reader.Read())
{
if (reader.Name == "Unit")
{
this.Unit = new Unit()
{
Name = reader.GetAttribute("Name"),
ID = reader.GetAttribute("ID")
};
break;
}
}
}
public XmlSchema GetSchema()
{
return(null);
}
}
I suspect that I'm performing the reading in a poor fashion, but this works in my local test. I still recommend separating your application and serialization concerns though and avoiding having to write an implementation like this.

You could try this:
public class Unit
{
public string Name { get; set; }
public string ID { get; set; }
}
public class Producing_Unit
{
public Unit Unit { get; set; }
}
public class Produced_by
{
private Producing_Unit producing_unit;
public Producing_Unit Producing_Unit //This can't be auto-implemented since can write to properties of properties.
{
get { return producing_Unit; }
set { producing_Unit = value; }
}
[XmlIgnoreAttribute]
public Unit Unit
{
get { return producing_Unit.Unit; }
set { producing_Unit.Unit = value; }
}
}
Yes, it doesn't get rid of the 'middle-men,' but you can ignore them.

Related

Is it possible to have extra (ignored) properties in C#?

I have a repository for a DocumentDb database. My documents all have a set of common properties so all documents implement the IDocumentEntity interface.
public interface IDocumentEntity {
[JsonProperty("id")]
Guid Id { get; set; }
[JsonProperty("documentClassification")]
DocumentClassification DocumentClassification { get; set; }
}
public class KnownDocument : IDocumentEntity {
[JsonProperty("id")]
Guid Id { get; set; }
[JsonProperty("documentClassification")]
DocumentClassification DocumentClassification { get; set; }
[JsonProperty("knownProperty")]
string KnownProperty { get; set; }
}
public class BaseDocumentRepository<T> where T : IDocumentEntity {
public Set(T entity) {
// ... stuff
}
}
This works fine with a KnownDocument where I know all of the properties. But, of course, what's great about a Document Db is that I don't need to know all of the properties (and in many cases I won't).
So my client submits something like this-
{unknownProperty1: 1, unknownProperty2: 2}
And I want to upsert this using my document repository.
public OtherDocumentService() {
_otherDocumentService = new OtherDocumentRepository();
}
public UpsertDocument(dynamic entity) {
entity.id = new Guid();
entity.documentClassification = DocumentClassification.Other;
_otherDocumentRepository.Set(entity);
}
But I get an InvalidCastException from dynamic to IDocumentEntity. I assume it's because of the extra properties that exist on the dynamic object but not on the IDocumentEntity interface?
What I'm trying to do is leave my document entities open to be dynamic, but rely on a few properties being there to maintain them.
Entity parameter passed to the UpsertDocument should explicitly implement IDocumentEntity in order do make the code works, it is not enough just have a Id property.
Some options:
1) Proxy may be applied:
public class ProxyDocumentEntity : IDocumentEntity
{
public dynamic Content { get; private set; }
public ProxyDocumentEntity(dynamic #content)
{
Content = #content;
}
public Guid Id
{
get { return Content.Id; }
set { Content.Id = value; }
}
}
... using
public void UpsertDocument(dynamic entity)
{
entity.Id = new Guid();
repo.Set(new ProxyDocumentEntity(entity));
}
The stored document will have nested Object property, which may be not acceptable
2)There is a lib https://github.com/ekonbenefits/impromptu-interface which creates a proxy dynamically
and does not make extra property like solution above.
Drawback will be in performance.
Technically it could be 2 methods:
public void UpsertDocument(IDocumentEntity entity){...}
public void UpsertDocument(dynamic entity){...}
so the first (fast) will work for the objects which implement IDocumentEntity and second(slow) for the rest of the objects.
But this is a speculation a bit , as I dunno the details of the whole code base of the project you have.
If you have some flexibility as to how to name those dynamic properties, you could stuff them into a Dictionary property on your object:
public Dictionary<string, dynamic> extra { get; set; }

How to Perform Unit testing for Serialization and Deserialization of a class in C#?

I want to perform NUnit or MS tests on a class for serialized and deserialized behavior.
I looked at another stackoverflow article here, but I still don't understand how to do this. Please help me to understand how to perform these tests,
Below is my part of code:
namespace PMT.Service.Common.DataContract
{
public partial class MyBankInfo
{
public string MyId { get; set; }
public string MyAccountNumber { get; set; }
public string MyAccountType { get; set; }
public string MyBankName { get; set; }
public string MyBankBranchName { get; set; }
public string MyBankCity { get; set; }
public string MyBankCityPincode { get; set; }
public string MyBankIFSCCode { get; set; }
public void Serialize(BinaryStreamWriter binaryStreamWriter)
{
binaryStreamWriter.Write(MyId);
binaryStreamWriter.Write(MyAccountNumber);
binaryStreamWriter.Write(MyAccountType);
binaryStreamWriter.Write(MyBankName);
binaryStreamWriter.Write(MyBankBranchName);
binaryStreamWriter.Write(MyBankCity);
binaryStreamWriter.Write(MyBankCityPincode);
binaryStreamWriter.Write(MyBankIFSCCode);
}
public bool Deserialize(BinaryStreamReader binaryStreamReader,out string errorString)
{
errorString = string.Empty;
try
{
MyId = binaryStreamReader.ReadString();
MyAccountNumber = binaryStreamReader.ReadString();
MyAccountType = binaryStreamReader.ReadString();
MyBankName = binaryStreamReader.ReadString();
MyBankBranchName = binaryStreamReader.ReadString();
MyBankCity = binaryStreamReader.ReadString();
MyBankCityPincode = binaryStreamReader.ReadString();
MyBankIFSCCode = binaryStreamReader.ReadString();
}
catch (Exception ex)
{
errorString = ex.Message;
}
return string.IsNullOrEmpty(errorString);
}
}
}
There are two ways to test serialization and deserialization: separately or both together.
Separate tests are best if the serialized data is created by or used by some other software that you don't have control over. In that case, exact formats have to be verified. This is also the hard way.
If your data is only serialized and deserialized by your own class, then you can test both at once:
Create a test object
Create a Writer in memory or backed on disk.
Serialize to that writer.
Create a second object and deserialize it from the saved data.
Write a bunch of assertions that compare the original object's properties to the new object's.

C# XML Serialization removing wrapper element

I wrote because I have problem with XmlSerializer. I want XML in the following format:
<?xml version="1.0" encoding="utf-8"?>
<RootXML>
<e-Invoice>
<Version>1.03</Version>
</e-Invoice>
<TradeInvoice>
<Id>1</Id>
<Value>100</Value>
</TradeInvoice>
<e-Invoice>
<Version>1.03</Version>
</e-Invoice>
<TradeInvoice>
<Id>2</Id>
<Value>200</Value>
</TradeInvoice>
<e-Invoice>
<Version>1.03</Version>
</e-Invoice>
<TradeInvoice>
<Id>3</Id>
<Value>300</Value>
</TradeInvoice>
</RootXML>
So I created the following classes.
[XmlRoot("RootXML")]
public class Root
{
public Root()
{
RootBodies = new List<RootBody>();
}
[XmlElement("e-Invoice")]
public List<RootBody> RootBodies { get; set; }
}
public class RootBody
{
public RootBody()
{
TradeInvoice = new TradeInvoice();
EInvoiceInfo = new Version(); ;
}
[XmlElement("e-Invoice")]
public Version EInvoiceInfo { get; set; }
[XmlElement("TradeInvoice")]
public TradeInvoice TradeInvoice { get; set; }
}
public class Version
{
[XmlElement("Version")]
public string Version { get; set; }
}
public class TradeInvoice
{
[XmlElement("Id")]
public int Id { get; set; }
[XmlElement("Value")]
public int Value { get; set; }
}
I have problem with removing wraper Elements (remove RootBody). I read similar topic like this link. But it does not solve my problem.
Before the actual explanation, let me point out a couple of very important things:
This XML is not very well designed and will cause a lot of other problems along the line (I'm guessing it is actually a lot more complicated than this).
The naming convention is inconsistent (e-Invoice and TradeInvoce)
The version number looks out of place, make sure this is really what they (whoever told you to do this) want before investing additional time.
This XML defines no namespaces (and probably doesn't have an XSD or DTD either)
Take a look at Google's XML design guidelines. You'll realize there is a lot of room for improvement.
There are a lot of different ways to do this, this is just one of them. I recommend you instead take it up with whoever is responsible for this design and try to change their mind.
Since you want to serialize e-Invoice and TradeInvoce without a wrapper element but still keep the order of elements (because they belong together) you need to make sure they have a common base class so they can be serialized from the same collection.
This abstract Invoice class simply tells the serializer which classes should be included during serialization via the XmlInclude attribute.
[XmlInclude(typeof(EInvoice))]
[XmlInclude(typeof(TradeInvoice))]
public abstract class Invoice
{
}
Your actual classes will be mostly unchanged
[XmlRoot("e-Invoice")]
public class EInvoice : Invoice
{
[XmlElement("Version")]
public string Version { get; set; }
}
[XmlRoot("TradeInvoice")]
public class TradeInvoice : Invoice
{
[XmlElement("Id")]
public int Id { get; set; }
[XmlElement("Value")]
public int Value { get; set; }
}
Your data class doesn't need any XML-related Attributes anymore because as it is now, it can't be serialized into that format directly.
public class InvoicePair
{
public InvoicePair(EInvoice eInvoice, TradeInvoice tradeInvoice)
{
TradeInvoice = tradeInvoice;
EInvoiceInfo = eInvoice;
}
public EInvoice EInvoiceInfo { get; set; }
public TradeInvoice TradeInvoice { get; set; }
}
Your Root class has to be simplified a bit. Since we want EInvoce and TradeInvoice Elements on the same level but mixed together, we need to put them in the same collection. The XmlElement attributes will tell the serializer how to handle elements of different types without relying on the xsi:type attribute.
[XmlRoot("RootXML")]
public class Root
{
public Root()
{
RootBodies = new List<Invoice>();
}
[XmlElement(Type = typeof(EInvoice), ElementName = "e-Invoice")]
[XmlElement(Type = typeof(TradeInvoice), ElementName = "TradeInvoice")]
public List<Invoice> RootBodies { get; set; }
}
Serialization is quite straight-forward at this point. Simply add all elements to the collection of elements one after another:
public static void Serialize(IEnumerable<InvoicePair> invoices, Stream stream)
{
Root root = new Root();
foreach (var invoice in invoices)
{
root.RootBodies.Add(invoice.EInvoiceInfo);
root.RootBodies.Add(invoice.TradeInvoice);
}
XmlSerializer serializer = new XmlSerializer(typeof(Root));
serializer.Serialize(stream, root);
}
Deserialization isn't very hard either, but very prone to erros and makes a lot of assumptions:
public static IEnumerable<InvoicePair> Deserialize(Stream stream)
{
XmlSerializer serializer = new XmlSerializer(typeof(Root));
Root root = serializer.Deserialize(stream) as Root;
for (int i = 0; i < root.RootBodies.Count; i += 2)
{
yield return new InvoicePair(
(EInvoice) root.RootBodies[i],
(TradeInvoice) root.RootBodies[i+1]
);
}
}
Here is a working Demo Fiddle, that outputs the XML

Disable emmiting empty list elements in Xml Serializer in C#

I would like to disable emmiting empty elements in Xml in List.
I know about PropertyNameSpecified pattern but I don't know how to apply it to the list.
I have list of elements and it is being serialized. Some of those elements are empty and are producing empty Xml elements in that list (what I don't want).
My sample code:
public class ConditionsCollectionModel
{
[XmlElement("forbidden")]
public List<ForbiddenModel> ForbiddenCollection { get; set; }
[XmlElement("required")]
public List<RequiredModel> RequiredCollection { get; set; }
}
public class ForbiddenModel : IXmlSerializable
{
public string Value { get; set; }
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
Value = reader.ReadElementString("forbidden");
}
public void WriteXml(XmlWriter writer)
{
writer.WriteString(Value);
}
}
public class RuleModel
{
[XmlElement("name")]
public string Name { get; set; }
[XmlElement("conditions")]
public ConditionsCollectionModel Conditions { get; set; }
}
It produces Xml in form like:
<rule>
<name>SR</name>
<conditions>
<forbidden />
<forbidden />
<forbidden>Ftest</forbidden>
<required>test</required>
<required>test2</required>
</conditions>
</rule>
I don't want those empty elements in conditions list.
The question is rather old but I experienced the same problem today. So for anybody reading this topic, this is the solution that works for me.
Add "ShouldSerialize{PropertyName}"
public class ConditionsCollectionModel
{
[XmlElement("forbidden")]
public List<ForbiddenModel> ForbiddenCollection { get; set; }
[XmlElement("required")]
public List<RequiredModel> RequiredCollection { get; set; }
public bool ShouldSerializeForbiddenCollection(){
return (ForbiddenCollection !=null && ForbiddenCollection.Count>0);
}
see: MSDN
Since ForbiddenCollection is list of Forbidden Class, you can set value of an empty ForbiddenClass object to null while inserting into the List.

.NET Serialization Ordering

I am trying to serialize some objects using XmlSerializer and inheritance but I am having some problems with ordering the outcome.
Below is an example similar to what I have setup: ~
public class SerializableBase
{
[XmlElement(Order = 1)]
public bool Property1 { get; set;}
[XmlElement(Order = 3)]
public bool Property3 { get; set;}
}
[XmlRoot("Object")]
public class SerializableObject1 : SerializableBase
{
}
[XmlRoot("Object")]
public class SerializableObject2 : SerializableBase
{
[XmlElement(Order = 2)]
public bool Property2 { get; set;}
}
The outcome I want is as follows: ~
<Object>
<Property1></Property1>
<Property2></Property2>
<Property3></Property3>
</Object>
However I am getting an outcome of: ~
<Object>
<Property1></Property1>
<Property3></Property3>
<Property2></Property2>
</Object>
Does anyone know if it is possible or of any alternative?
Thanks
Technically, from a pure xml perspective, I would say that this is probably a bad thing to want to do.
.NET hides much of the complexity of things like XmlSerialization - in this case, it hides the schema to which your serialized xml should conform.
The inferred schema will use sequence elements to describe the base type, and the extension types. This requires strict ordering -- even if the Deserializer is less strict and accepts out of order elements.
In xml schemas, when defining extension types, the additional elements from the child class must come after the elements from the base class.
you would essentially have a schema that looks something like (xml-y tags removed for clarity)
base
sequence
prop1
prop3
derived1 extends base
sequence
<empty>
derived2 extends base
sequence
prop2
There's no way to stick a placeholder in between prop1 and prop3 to indicate where the properties from the derived xml can go.
In the end, you have a mismatch between your data format and your business object. Probably your best alternative is to define an object to deal with your xml serialization.
For example
[XmlRoot("Object")
public class SerializableObjectForPersistance
{
[XmlElement(Order = 1)]
public bool Property1 { get; set; }
[XmlElement(Order = 2, IsNullable=true)]
public bool Property2 { get; set; }
[XmlElement(Order = 3)]
public bool Property3 { get; set; }
}
This separates your xml serialization code from your object model. Copy all the values from SerializableObject1 or SerializableObject2 to SerializableObjectForPersistance, and then serialize it.
Essentially, if you want such specific control over the format of your serialized xml that doesn't quite jive with the expectations xml serialization framework, you need to decouple your business object design (inheritance structure in this case) and the responsibility for serialization of that business object.
EDIT: This approach doesn't work. I've left the post in so that people can avoid this line of thinking.
The serializer acts recursively. There's a benefit to this; on deserialization, the deserialization process can read the base class, then the derived class. This means that a property on the derived class isn't set before the properties on the base, which could lead to problems.
If it really matters (and I'm not sure why it's important to get these in order) then you can try this --
1) make the base class' Property1 and Property3 virtual.
2) override them with trivial properties in your derived class. Eg
public class SerializableBase
{
[XmlElement(Order = 1)]
public virtual bool Property1 { get; set;}
[XmlElement(Order = 3)]
public virtual bool Property3 { get; set;}
}
[XmlRoot("Object")]
public class SerializableObject1 : SerializableBase
{
}
[XmlRoot("Object")]
public class SerializableObject2 : SerializableBase
{
[XmlElement(Order = 1)]
public override bool Property1
{
get { return base.Property1; }
set { base.Property1 = value; }
}
[XmlElement(Order = 2)]
public bool Property2 { get; set;}
[XmlElement(Order = 3)]
public override bool Property3
{
get { return base.Property3; }
set { base.Property3 = value; }
}
}
This puts a concrete implementtion of the property on the most derived class, and the order should be respected.
It looks like the XmlSerializer class serializes the base type and then derived types in that order and is only respecting the Order property within each class individually. Even though the order is not totally what you want, it should still Deserialize properly. If you really must have the order just like that you will need to write a custom xml serializer. I would caution against that beacuse the .NET XmlSerializer does a lot of special handling for you. Can you describe why you need things in the order you mention?
This post is quite old now, but I had a similar problem in WCF recently, and found a solution similar to Steve Cooper's above, but one that does work, and presumably will work for XML Serialization too.
If you remove the XmlElement attributes from the base class, and add a copy of each property with a different name to the derived classes that access the base value via the get/set, the copies can be serialized with the appropriate name assigned using an XmlElementAttribute, and will hopefully then serialize in the default order:
public class SerializableBase
{
public bool Property1 { get; set;}
public bool Property3 { get; set;}
}
[XmlRoot("Object")]
public class SerializableObject : SerializableBase
{
[XmlElement("Property1")]
public bool copyOfProperty1
{
get { return base.Property1; }
set { base.Property1 = value; }
}
[XmlElement]
public bool Property2 { get; set;}
[XmlElement("Property3")]
public bool copyOfProperty3
{
get { return base.Property3; }
set { base.Property3 = value; }
}
}
I also added an Interface to add to the derived classes, so that the copies could be made mandatory:
interface ISerializableObjectEnsureProperties
{
bool copyOfProperty1 { get; set; }
bool copyOfProperty2 { get; set; }
}
This is not essential but means that I can check everything is implemented at compile time, rather than checking the resultant XML. I had originally made these abstract properties of SerializableBase, but these then serialize first (with the base class), which I now realise is logical.
This is called in the usual way by changing one line above:
public class SerializableObject : SerializableBase, ISerializableObjectEnsureProperties
I've only tested this in WCF, and have ported the concept to XML Serialization without compiling, so if this doesn't work, apologies, but I would expect it to behave in the same way - I'm sure someone will let me know if not...
I know this question has expired; however, here is a solution for this problem:
The name of the method should always begin with ShouldSerialize and then end with the property name. Then you simply need to return a boolean based on whatever conditional you want, as to whether to serialize the value or not.
public class SerializableBase
{
public bool Property1 { get; set;}
public bool Property2 { get; set;}
public bool Property3 { get; set;}
public virtual bool ShouldSerializeProperty2 { get { return false; } }
}
[XmlRoot("Object")]
public class SerializableObject1 : SerializableBase
{
}
[XmlRoot("Object")]
public class SerializableObject2 : SerializableBase
{
public override bool ShouldSerializeProperty2 { get { return true; } }
}
The outcome when using SerializableObject2: ~
<Object>
<Property1></Property1>
<Property2></Property2>
<Property3></Property3>
</Object>
The outcome when using SerializableObject1: ~
<Object>
<Property1></Property1>
<Property3></Property3>
</Object>
Hope this helps many others!
Like Nader said, maybe think about making a more loose-coupled design. However, in my case, loose-coupling was not appropriate. Here's my class hierarchy, and how I propose to solve the problem without using custom serialization or DTOs.
In my project, I'm constructing a whole bunch of objects to represent pieces of an XML document that will be submitted via a web service. There are a very large number of pieces. Not all are sent with every request (actually, in this example, I'm modeling a response, but the concepts are the same). These pieces are used much like building blocks to assemble a request (or disassemble a response, in this case). So here's an example of using aggregation/encapsulation to accomplish the desired ordering despite the inheritance hierarchy.
[Serializable]
public abstract class ElementBase
{
// This constructor sets up the default namespace for all of my objects. Every
// Xml Element class will inherit from this class.
internal ElementBase()
{
this._namespaces = new XmlSerializerNamespaces(new XmlQualifiedName[] {
new XmlQualifiedName(string.Empty, "urn:my-default-namespace:XSD:1")
});
}
[XmlNamespacesDeclaration]
public XmlSerializerNamespaces Namespaces { get { return this._namespaces; } }
private XmlSerializationNamespaces _namespaces;
}
[Serializable]
public abstract class ServiceBase : ElementBase
{
private ServiceBase() { }
public ServiceBase(Guid requestId, Guid? asyncRequestId = null, Identifier name = null)
{
this._requestId = requestId;
this._asyncRequestId = asyncRequestId;
this._name = name;
}
public Guid RequestId
{
get { return this._requestId; }
set { this._requestId = value; }
}
private Guid _requestId;
public Guid? AsyncRequestId
{
get { return this._asyncRequestId; }
set { this._asyncRequestId = value; }
}
private Guid? _asyncRequestId;
public bool AsyncRequestIdSpecified
{
get { return this._asyncRequestId == null && this._asyncRequestId.HasValue; }
set { /* XmlSerializer requires both a getter and a setter.*/ ; }
}
public Identifier Name
{
get { return this._name; }
set { this._name; }
}
private Identifier _name;
}
[Serializable]
public abstract class ServiceResponseBase : ServiceBase
{
private ServiceBase _serviceBase;
private ServiceResponseBase() { }
public ServiceResponseBase(Guid requestId, Guid? asyncRequestId = null, Identifier name = null, Status status = null)
{
this._serviceBase = new ServiceBase(requestId, asyncRequestId, name);
this._status = status;
}
public Guid RequestId
{
get { return this._serviceBase.RequestId; }
set { this._serviceBase.RequestId = value; }
}
public Guid? AsyncRequestId
{
get { return this._serviceBase.AsyncRequestId; }
set { this._serviceBase.AsyncRequestId = value; }
}
public bool AsynceRequestIdSpecified
{
get { return this._serviceBase.AsyncRequestIdSpecified; }
set { ; }
}
public Identifier Name
{
get { return this._serviceBase.Name; }
set { this._serviceBase.Name = value; }
}
public Status Status
{
get { return this._status; }
set { this._status = value; }
}
}
[Serializable]
[XmlRoot(Namespace = "urn:my-default-namespace:XSD:1")]
public class BankServiceResponse : ServiceResponseBase
{
// Determines if the class is being deserialized.
private bool _isDeserializing;
private ServiceResponseBase _serviceResponseBase;
// Constructor used by XmlSerializer.
// This is special because I require a non-null List<T> of items later on.
private BankServiceResponse()
{
this._isDeserializing = true;
this._serviceResponseBase = new ServiceResponseBase();
}
// Constructor used for unit testing
internal BankServiceResponse(bool isDeserializing = false)
{
this._isDeserializing = isDeserializing;
this._serviceResponseBase = new ServiceResponseBase();
}
public BankServiceResponse(Guid requestId, List<BankResponse> responses, Guid? asyncRequestId = null, Identifier name = null, Status status = null)
{
if (responses == null || responses.Count == 0)
throw new ArgumentNullException("The list cannot be null or empty", "responses");
this._serviceResponseBase = new ServiceResponseBase(requestId, asyncRequestId, name, status);
this._responses = responses;
}
[XmlElement(Order = 1)]
public Status Status
{
get { return this._serviceResponseBase.Status; }
set { this._serviceResponseBase.Status = value; }
}
[XmlElement(Order = 2)]
public Guid RequestId
{
get { return this._serviceResponseBase.RequestId; }
set { this._serviceResponseBase.RequestId = value; }
}
[XmlElement(Order = 3)]
public Guid? AsyncRequestId
{
get { return this._serviceResponseBase.AsyncRequestId; }
set { this._serviceResponseBase.AsyncRequestId = value; }
}
[XmlIgnore]
public bool AsyncRequestIdSpecified
{
get { return this._serviceResponseBase.AsyncRequestIdSpecified; }
set { ; } // Must have this for XmlSerializer.
}
[XmlElement(Order = 4)]
public Identifer Name
{
get { return this._serviceResponseBase.Name; }
set { this._serviceResponseBase.Name; }
}
[XmlElement(Order = 5)]
public List<BankResponse> Responses
{
get { return this._responses; }
set
{
if (this._isDeserializing && this._responses != null && this._responses.Count > 0)
this._isDeserializing = false;
if (!this._isDeserializing && (value == null || value.Count == 0))
throw new ArgumentNullException("List cannot be null or empty.", "value");
this._responses = value;
}
}
private List<BankResponse> _responses;
}
So, while I have to create properties for all of the contained classes, I can delegate any custom logic I might have within the contained class(es) property setters/getters by simply using the contained class's properties when the leaf class's properties are accessed. Since there's no inheritance, I can decorate all the properties of the leaf class with the XmlElementAttribute attribute and use any ordering that I see fit.
UPDATE:
I came back to revisit this article because my design decisions about using class inheritance came back to bite me again. While my solution above does work, I'm using it, I really think that Nader's solution is the best and should be considered before the solution I presented. In fact, I'm +1'ing him today! I really like his answer, and if I ever have the opportunity to refactor my current project, I will definitely be separating the business object from the serialization logic for objects that would otherwise benefit greatly from inheritance in order to simplify the code and make it easier for others to use and understand.
Thanks for posting your response Nader, as I think many will find it very instructive and useful.

Categories