I have following domain model that I need to persist in database with help of Fluent NHibernate:
public class Entity
{
public Guid Id { get; set; }
public IValueObject AnyValueObject { get; set; }
}
public interface IValueObject
{
string Value { get; }
}
public class ValueObject : IValueObject
{
private readonly string _value;
public ValueObject(string value)
{
_value = value; // null checks omitted for brevity
}
public string Value { get { return _value; }}
}
public class AnotherValueObject : IValueObject
{
private readonly string _value;
private readonly string _anotherValue;
public AnotherValueObject(string value, string anotherValue)
{
_value = value; // null checks omitted for brevity
_anotherValue = anotherValue;
}
public string Value { get { return _value; } }
public string AnotherValue { get { return _anotherValue; } }
}
ValueObject and AnotherValueObject doesn't have any id and they're immutable.
The problem is that I have no idea how to write map for AnyValueObject property. I know that value objects must be mapped as Components, but how to deal with abstract immutable value objects?
You either have to give it an ID or avoid polymorphism, because NH doesn't support polymorphism for components and requires an ID for entities.
If it is a rather simple inheritance with just a few different classes and no logic, I would put it all in the same class. It much simpler anyway. Then you ca map it as a component. You could give it an enum to easily check the type it has.
If you really (really) need inheritance / polymorphism, you need to give it an ID.
Related
I have the following structure:
public class LogicStatement : ILogicStatement
{
public string TestLogic { get; set; }
public string CompareLogic { get; set; }
public string Operator { get; set; }
public string Expression();
public bool Value();
}
public class Test : ITest
{
public int TestId { get; set; }
public int LiteralId { get; set; }
public string TestName { get; set; }
public string TestText { get; set; }
public string TestDisplayName { get; }
**public ILogicStatement LogicStatement { get; set; }**
public string Expression { get; set; }
public bool Value { get; set; }
}
public class Literal : ILiteral
{
some property members...
**public List<ITest> Tests {get; set;}**
some method members...
}
Note that the class Test has a member of type LogicStatement, and the class Literal has a member of type List.
Note also that all classes have properties and methods that share the same name: Expression, Value, Expression(), Value().
The value of Expression and Value (properties and methods) depend on values in the LogicStatement class.
Throughout the whole project, I use the Interface Type for to instantiate each object to adhere with Dependency Inversion. To support this, I use a factory-like design to create new instances of Test and LogicStatement.
Example:
public static class Factory
{
public static ILogicStatement CreateLogicStatement()
{
return new LogicStatement();
}
public static ITest CreateTest()
{
return new Test(CreateLogicStatement());
}
public static List<ITest> CreateTests()
{
return new List<ITest>();
}
//repeat the same for evey other class.
}
My goal is to have Expression() and Value() be calculated only once in the bottom level class (LogicStatement), and somehow get transfered to their counterpart properties in the higher level classes.
I'm getting the data from Dapper and it looks like all the nested objects are returned from the Dapper module correctly with the same nested structure I intended, and with the right values for all of their members. All of them but Expression, Expression(), Value, Value() are null.
my constructors look like this:
public LogicStatement()
{
Expression();
Value();
}
public Test(ILogicStatement logicStatement)
{
_logicStatement = logicStatement;
Expression = _logicStatement.Expression();
Value = _logicStatement.Value();
}
public Literal(ITest test)
{
_test = test;
Expression = _test.Expression;
Value = _test.Value;
}
and my main:
List<ILiteral> literals = Factory.CreateLiterals();
List<ITest> tests = Facotry.CreateTests();
List<ILogicStatement> logicStatements = Factory.CreateLogicStatements();
literals = GetDataFromDapper();
This last line seems to assign correct values to all other members on all hierarchies. But I cannot get Expression and Value to be anything other than null.
If I test LogicStatement.Expression() and LogicStatement.Value() standalone, they do return the expexted values. but starting at the first parent class Test, these properties are all null.
I think I'm doing something wrong in the way i'm instantiating my objects. Primarily because I'm not sure i understand basic best practices to write constructors.
Maybe I the desired behavior should be implemented through events, where the Test and Literal classes subscribe to changes in the Expression() and Value() methods (or rather to what calculates them). But I never used events and I'd like to know if this fundamentally can be acheived without them first.
My question: How do I make the Expression() Value() at the bottom level class "Fire up" whenever LogicStatement is instantiated, and then have the Expression and Value properties be assigned accordingly as a result.
In other words, I want the following to always be true:
test[i].Expression == literal[i].Expression == LogicStatement[i].Expression()
I'm a beginner in OOP. So any fundamental explanation is welcome.
As you are new to object oriented programming I would start with the basics and leave factories and adhering with Dependency Inversion and the interfaces away for later.
You could tell Dapper to split joined tables into multiple entities (see https://www.learndapper.com/relationships), but for learning OOP I would start doing everything manually.
Your class design does not look proper to me yet. Not sure what Expression and Value of the LogicStatement are, but if they are calculations based on the other properties, I would implement them as (just to show off with complicated words) lazy initialized cached getter properties that are invalidated in the setters of the relevant properties. That ensures you only calculate them once for as many reads you like but recalculate them on first read after one or multiple properties have been updated.
public class LogicStatement {
private string _testLogic;
private string _compareLogic;
private string _operator;
private string? _expression;
private bool? _value;
public LogicStatement(string testLogic, string compareLogic, string #operator) {
_testLogic = testLogic;
_compareLogic = compareLogic;
_operator = #operator;
}
public string TestLogic {
get {
return _testLogic;
}
set {
_testLogic = value;
InvalidateCachedValues();
}
}
public string CompareLogic {
get {
return _compareLogic;
}
set {
_compareLogic = value;
InvalidateCachedValues();
}
}
public string Operator {
get {
return _operator;
}
set {
_operator = value;
InvalidateCachedValues();
}
}
public string Expression {
get {
string? result = _expression;
if (result is null) {
_expression = result = BuildExpression();
}
return result;
}
}
public bool Value {
get {
bool? result = _value;
if (result is null) {
_value = result = EvaluateValue();
}
return result.Value;
}
}
private void InvalidateCachedValues() {
_expression = null;
_value = null;
}
private string BuildExpression() {
//Your logic goes here
throw new NotImplementedException();
}
private bool EvaluateValue() {
//Your logic goes here
throw new NotImplementedException();
}
}
Sorry, it got a bit bigger with the full properties.
In the other classes I would not copy the Value and the Expression but simply remove these properties as anybody can easily access them through the LogicStatement property:
public class Test {
public Test(int testId, int literalId, string testName, string testText, string testDisplayName, LogicStatement logicStatement) {
TestId = testId;
LiteralId = literalId;
TestText = testText;
TestDisplayName = testDisplayName;
LogicStatement = logicStatement;
}
public int TestId { get; }
public int LiteralId { get; }
public string TestName { get; }
public string TestText { get; }
public string TestDisplayName { get; }
public LogicStatement LogicStatement { get; }
}
and the Literal could look like this (I got a bit confused whether this class has one Test or a list of them, I stick to your constructor + properties that hint in the direction of a single one):
public class Literal {
private Test _test;
public Literal(string property1, int property2, Test test) {
Property1 = property1;
Property2 = property2;
_test = test;
}
public string Property1 { get; }
public int Property2 { get; }
public string Expression => _test.LogicStatement.Expression;
public bool Value => _test.LogicStatement.Value;
}
As you decided not to expose the Test in the Literal it makes sense to provide Expression and Value, otherwise they could also be removed (or kept for convenience).
Issue origin: I have a generic component to display data. The data may come from different data models. To unify the access inside the component I created one interface IOne that gets implemented by all classes. In order to abstract the data access layer from the application I'm using interfaces for each data model. So each data display model implements the IOne interface and additionally one of the data model interfaces.
The interfaces:
public interface IOne
{
public int idNameOne { get; set; }
}
public interface DataModelOne
{
public int anotherNameForId{ get; set; }
}
In my class I want both members to be satisfied by one single property. My current solution is as follows:
public class Implementation : IOne, DataModelOne
{
private int _id;
public idNameOne { get { return _id; } set { _id = value; } }
public anotherIdName { get { return _id; } set { _id = value; } }
}
Is there any way to declare that one property satisfies both members? What would be a clean solution for this?
No, there's no other way than what you are doing. I'd however clean up the code (and do proper casing), by removing the backing field (and use one auto-property) and only have the other one reference the first... something like:
public class Implementation : IOne, IDataModelOne
{
public int IdNameOne { get; set }
public int AnotherIdName { get => IdNameOne; set => IdNameOne = value; }
}
(notice I've used the proper casing for the properties... should be the same casing on the interfaces too... also named IDataModelOne correctly, with an I prefix)
To avoid having both on the public API, you should usually use "explicit interface implementation" for this, for example:
public class Implementation : IOne, DataModelOne
{
public int idNameOne { get; set; }
int DataModelOne.anotherNameForId
{
get => idNameOne;
set => idNameOne = value;
}
}
or
public class Implementation : IOne, DataModelOne
{
public int Id { get; set; }
int IOne.idNameOne
{
get => Id;
set => Id = value;
}
int DataModelOne.anotherNameForId
{
get => Id;
set => Id = value;
}
}
If I really had to do this I would make the idNameOne property an auto property with anotherIdName's getter and setter referring to that property.
public class Implementation : IOne, DataModelOne
{
public idNameOne { get; set; }
public anotherIdName { get { return idNameOne; } set { idNameOne = value; } }
}
It's a little bit cleaner and show the intention a little better too.
I have a class representing sensors in a plant. For historical reasons, similar objects (that are therefore represented by the same class) have a different identification:
Some have a name (ie. "north-west-gummy-bear")
Some have an areaId, and a sensorId
In order to accomodate for this, I use an empty interface:
public class sensor
{
ISensorIdentifier id{get;set;}
}
public interface ISensorIdentifier{
}
public class namedSensorID:ISensorIdentifier{
string name{get;set;}
}
public class idSensorID:ISensorIdentifier{
int areaID{get;set;}
int sensorID{get;set;}
}
This allows me to use the same class for objects with a different identification system.
It is my understanding that empty interfaces are a code smell, and that I should use custom attributes instead.
However, after reading about custom attributes, I have no idea where to start. Indeed, I could use a custom attribute 'sensorIdentifier' instead of the empty interface, but how should I type the id property in the sensor class?
Well you can consider that a sensor has one unique valid identifier information (using c#7 native tuple support):
(Name, AreaId, SensorId)
Your business logic should enforce that valid id information must be:
(Name, null, null)
Or
(null, AreaId, SensorId)
Anything else is not valid. Ok, lets build a base class that enforces this:
public abstract class Sensor
{
private readonly string name;
private readonly int? areaId, sensorId;
protected Sensor(string name)
{
this.name = name;
}
protected Sensor(int areaId, int sensorId)
{
this.areaId = areaId;
this.sensorId = sensorId;
}
public (string Name, int? AreaId, int? SensorId) Id
{
get
{
Debug.Assert(
(name != null && !(areaId.HasValue || sensorId.HasValue)) ||
(name == null && (areaId.HasValue && sensorId.HasValue)));
return (name, areaId, sensorId);
}
}
}
Your specific sensor implementations are trivial, extending Sensor:
public class NamedSensor: Sensor
{
public NamedSensor(string name)
:base(name)
{ }
}
public class IdSensor: Sensor
{
public IdSensor(int areaId, int sensorId)
:base(areaId, sensorId)
{ }
}
And you can happily work with an IEnumerable<Sensor>.
I propose that you add a unique identifier in your empty interface which should be implemented in each of your concrete classes:
public interface ISensorIdentifier
{
string UniqueSensorId { get; }
}
You should simply ensure that these implementations in the different sub classes make this new ID unique. Here is a quick proposal:
public class namedSensorID : ISensorIdentifier
{
public string UniqueSensorId { get { return nameof(namedSensorID) + name; } }
string name { get; set; }
}
public class idSensorID : ISensorIdentifier
{
int areaID { get; set; }
int sensorID { get; set; }
public string UniqueSensorId { get { return nameof(idSensorID) + areaID + sensorID; } }
}
I'm trying to implement the ITableEntity interface so that I can add [DataContract] attribute on it. But if I implement this interface myself, I'll have to give the ReadEntity and WriteEntity methods a body.
But there is a class that already implements the ITableEntity interface and gave ReadEntity and WriteEntity methods a body, which is the TableEntity.cs.
How can I make my implementation of the interface use the methods in the TableEntity class?
[Edit]
[DataContract]
public class SerializableTableEntity : ITableEntity
{
private TableEntity tableEntity;
public string ETag { get; set; }
public string PartitionKey { get; set; }
public string RowKey { get; set; }
public DateTimeOffset Timestamp { get; set; }
public SerializableTableEntity()
{
tableEntity = new TableEntity();
}
public void ReadEntity(IDictionary<string, EntityProperty> properties, Microsoft.WindowsAzure.Storage.OperationContext operationContext)
{
tableEntity.ReadEntity(properties, operationContext);
}
public IDictionary<string, EntityProperty> WriteEntity(Microsoft.WindowsAzure.Storage.OperationContext operationContext)
{
return tableEntity.WriteEntity(operationContext);
}
}
The reason that every property in your stored table is blank is because WriteEntity and ReadEntity use the blank object to store and write the data.
You're delegating serialization of your object to 'tableEntity' but none of your properties are there.
Suggestion: you will need to implement all of your SerializableTableEntity's properties inside a class that derives from TableEntity, contain a variable of that type inside the SerializableTableEntity entity, and delegate every member's property get/set from SerializableTableEntity to this new object.
Does this make sense?
EDIT: Code sample as requested (you're not going to enjoy it though)
[DataContract]
public class SerializableTableEntity : ITableEntity
{
private CustomEntity tableEntity;
public string ETag {
{
get
{
return tableEntity.ETag;
}
set
{
tableEntity.Etag = value;
}
}
public string PartitionKey
{
get
{
return tableEntity.PartitionKey;
}
set
{
tableEntity.PartitionKey = value;
}
}
public string RowKey
{
get
{
return tableEntity.RowKey;
}
set
{
tableEntity.RowKey = value;
}
}
public DateTimeOffset Timestamp
{
get
{
return tableEntity.Timestamp;
}
set
{
tableEntity.Timestamp = value;
}
}
public string PropertyOne
{
get
{
return tableEntity.PropertyOne;
}
set
{
tableEntity.PropertyOne = value;
}
}
public SerializableTableEntity()
{
tableEntity = new CustomEntity();
}
public void ReadEntity(IDictionary<string, EntityProperty> properties, Microsoft.WindowsAzure.Storage.OperationContext operationContext)
{
tableEntity.ReadEntity(properties, operationContext);
}
public IDictionary<string, EntityProperty> WriteEntity(Microsoft.WindowsAzure.Storage.OperationContext operationContext)
{
return tableEntity.WriteEntity(operationContext);
}
}
public class CustomEntity : TableEntity
{
public string PropertyOne { get; set; }
}
I ended up creating exact copy of these classes and made them Serializable. But being able to do some complex queries seems to be a challenge as well. So we moved to SQL Database.
Either delegate the "uninteresting" methods (a more realistic example is here):
class YourClass : Interface {
public void ReadEntity()
{
delegateTo.ReadEntity();
}
TableEntity delegateTo = new TableEntity();
}
or just throw an exception inside them (like NotImplementedException) - the latter will only work for you if those methods are not called.
You can create a class that contains the implementation of the TableEntity class, but also adds the functionality that you want. This is similar to the Decorator Pattern.
[Attributes...]
public class MyTableEntity : ITableEntity {
private TableEntity decoratedTableEntity;
public void ReadEntity(args...) {
decoratedTableEntity.ReadEntity(args...);
}
}
To make the solution more generic, change decoratedTableEntity to be an ITableEntity.
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.