I have a parent class that I want to have many flat children. That means 10 or more different classes would inherent from one class.
Here is what I have.
Base Class:
[ProtoContract]
[ProtoInclude(500, typeof(Message1Send))]
[ProtoInclude(501, typeof(Message2Send))]
public class MessageBase
{
[ProtoMember(1)]
public string Topic {get;set;}
[ProtoMember(2)]
public string Action { get; set; }
}
2 of many Child Classes:
[ProtoContract]
public class Message1Send : MessageBase
{
[ProtoMember(1)]
public string Property1 { get; set; }
}
[ProtoContract]
public class Message2Send : MessageBase
{
[ProtoMember(1)]
public string Property1 { get; set; }
}
I want to be able to tell the child object I am part of a base class.
I don’t what to get to the point where my base class is as follows:
[ProtoContract]
[ProtoInclude(500, typeof(Message1Send))]
[ProtoInclude(501, typeof(Message2Send))]
[ProtoInclude(502, typeof(Message3Send))]
[ProtoInclude(503, typeof(Message4Send))]
[ProtoInclude(504, typeof(Message5Send))]
[ProtoInclude(505, typeof(Message6Send))]
[ProtoInclude(506, typeof(Message7Send))]
[ProtoInclude(507, typeof(Message8Send))]
[ProtoInclude(508, typeof(Message9Send))]
[ProtoInclude(509, typeof(Message10Send))]
public class MessageBase
{
[ProtoMember(1)]
public string Topic {get;set;}
[ProtoMember(2)]
public string Action { get; set; }
}
Is there a way I can have each one of the Send classes to just add one reference to the base class so I don’t have to keep adding ProtoInclude for every flat child I create?
The problem is one of reliability. Reflection makes veryfew repeatable / reliable guarantees, and it is very important that if you serialize data today, then edit your app to add two new types, each type still has the same number as it did oroginally. Even if you've added some new types, renamed some, and possibly removed two that you weren't really using.
The attribute guarantees this by making the field-number repeatable. The reason it is on the parent (not the child) is that it is much more reliable to walk up the type-chain than down it.
However: if you have a reliable repeatable way of generating field numbers for sub-types, you can use RuntimeTypeModel to configure the serializer to your liking.
Related
I have a class Thing that is deserialized from a JSON file using DataContractJsonSerializer:
[DataContract]
class Thing
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
// and so on...
}
To make this work, all properties need to have public or at least internal setters.
Two other modules (assemblies) need to access this class:
ThingView should have read-only access to most attributes.
ThingEditor needs full access to all attributes.
I could make the setters internal but then the ThingEditor would not get full access.
To restrict access for the ThingView class, the best idea I could come up with is to create a read-only wrapper of the Thing class. But this would involve a lot of code duplication.
Are there better ways to achieve more encapsulation for in a case like this?
(The actual code contains about 20 classes of this type, some of which form nested structures. Also, there are more than two modules that need either read or full access to the properties.)
There is nothing out of the box in the specs that would achieve this. However, you could do something like this for example
public interface IReadOnlInterface
{
int Id { get; }
string Name { get; }
}
public interface IInterface
{
int Id { get; set; }
string Name { get; set; }
}
internal class Thing : IInterface , IReadOnlInterface
{
public int Id { get; set; }
public string Name { get; set; }
}
However there is nothing stopping coders with dirty little fingers casting to the other interface. If its only a runtime issue, then interfaces should be fine. Otherwise youll have to create a better api design with secured data, and proxy type objects with readonly access, Though maybe someone has a better idea.
i have an abstract model named BetaModel that inherit its parent AlphaModel. Then
I have a bunch of request models that inherit the BetaModel and therefore naturally inherit AlphaModel, However I have the other bunch of response models which have to inherit the fields of BetaModel and do not need the fields in AlphaModel.
[Note: AlphaModel and BetaModel only contain some plain fields]
What is the elegant way to have the response models inherit the BetModel but ignore the AlphaModel?
Is it OK to turn the AlphaModel becomes an Interface, so that it only implemented in all the request models but not the response models?
So, you are basically contradicting the description with the "desired" architecture.
Also, always bare in mind that you don't decide architecture based on results ("Is it OK to turn the AlphaModel becomes an Interface"): your decisions are based on needs and responsibilities.
Interfaces
Think of that as a contract the classes are agreeing with. They don't hold any implementations and solely describe one contract the class implements
Abstract Classes
They are... Classes. As such, they don't define a contract, they define behaviours. And mostly, when defining an abstract class, you are looking for a abstract behaviour that you want children classes to inherit and/or give meaning to.
Your problem
You are saying some classes must inherit from AlphaModel and some others must NOT inherit from AlphaModel.
Therefore, you are saying that:
A certain class BetaModel1 inherits from AlphaModel and introduces some new members functionality.
Another class BetaModel2 should not expose any member from AlphaModel (which screams it doesn't inherit from AlphaModel) but also introduces the same members/functionality of BetaModel1
In other words, you are saying with all capital letters that BetaModel1 and BetaModel2 DO NOT INHERIT FROM THE SAME CLASS AlphaModel.
Now, back to our initial discussion. C# does not allow multiple inheritance (which looks like what you want to do). But there are strategies either to minimise re-writing code and/or enforce some implementations.
So, the "enforcing of implementation" is basically saying "I want this class to NECESSARILY provide certain functionality". Well... You need an interface for that
C#
public interface IBetaModel
{
string PropertyBeta { get; set; }
string MethodBeta();
}
There is also the AlphaModel
C#
public class AlphaModel
{
public string PropertyAlpha { get; set; }
public string MethodAlpha()
{
return "This is Alpha";
}
}
Now, your desired BetaModel1 (as described above) is quite simply inheriting from AlphaModel and implementing IBetaModel
C#
public class BetaModel1 : AlphaModel, IBetaModel
{
public string PropertyBeta { get; set; }
public string MethodBeta()
{
return "This is Beta?";
}
}
BetaModel2 it's just implementing IBetaModel, in which case:
C#
public class BetaModel2 : IBetaModel
{
public string PropertyBeta { get; set; }
public string MethodBeta()
{
return "This is Beta?";
}
}
The usage of the classes would be like:
C#
public void DoStuffWith(IBetaModel betaModel)
{
betaModel.PropertyBeta = "WOW, it works";
}
public void DoStuff()
{
var betaModel1 = new BetaModel1();
var betaModel2 = new BetaModel2();
AlphaModel betaModel1_ = new BetaModel1();
//AlphaModel betaModel2_ = new BetaModel2(); //won't compile
betaModel1.PropertyAlpha = "Test";
//betaModel2.PropertyAlpha = "Test"; //won't compile
DoStuffWith(betaModel1); //great!!!
DoStuffWith(betaModel2); //great too!!!
}
If this is only about data make every datapart an interface like...
public interface IAlphaModel
{
string SomeField { get; set; }
}
public interface IBetaModel
{
int AnotherField { get; set; }
}
public interface ISomeRequest : IAlphaModel, IBetaModel
{
bool YetAnotherField { get; set; }
}
class SomeRequest : ISomeRequest
{
public string SomeField { get; set; }
public int AnotherField { get; set; }
public bool YetAnotherField { get; set; }
}
public interface IAnotherRequest : IBetaModel
{
long TheUltimateField { get; set; }
}
class AnotherRequest : IAnotherRequest
{
public int AnotherField { get; set; }
public long TheUltimateField { get; set; }
}
Edit
Of course you can have the interfaces have more than one member if they are tied logically together.
I need to model organizational hierarchy structure in my entities. An organization can be head-office, regional head, sub region, area office. There are a lot of common functions that the organizations are performing, but there are several functions that are specific for example only Regions can perform task A. There is also some properties(data) that is specific to Region.
I modeled it using composition and not using inheritance, but now I have ended with only a single organization class, with lot of references which depending on the TYPE of organization can have valid references or be null.
Object composition was a pain which now I am handling through factories. But now my main concern is the developers need to remember what the organization type is and whether a property has some meaning for that organization or not.
Just to be clear what I mean.
public class Organization : IKeyed<int> {
public virtual int Id { get; protected set; }
public virtual string Code { get; set; }
public virtual OrganizationType orgType {get;set;}
public virtual Organization Parent {get;set;}
public virtual IList<Organization> Children {get;set;}
public virtual typeA {get; set;} // only meaningful when organization type is 'Head office'
public virtual typeB {get;set;}// only meaningful when 'Region'
public virtual void AddChild(Organization org){...}
...
}
Should I have used inheritance over here? Or am I missing some tricks here?
In my opinion, I suggest you create an abstract base class that hold common behaviors and fields. Then you can add sub-classes to extend more specific behavior and/or properties.
public abstract class Organization : IKeyed<int> {
public virtual int Id { get; protected set; }
public virtual string Code { get; set; }
// remove this property
// public virtual OrganizationType orgType {get;set;}
public virtual Organization Parent {get;set;}
public virtual IList<Organization> Children {get;set;}
// move this property to sub-class
// public virtual typeA {get; set;} // only meaningful when organization type is 'Head office'
// move this property to sub-class
// public virtual typeB {get;set;}// only meaningful when 'Region'
public virtual void AddChild(Organization org){...}
...
}
public class HeadOffice : Organization
{
public virtual typeA { get; set; }
}
public class Region : Organization
{
public virtual typeB { get; set;}
}
public class OtherOrganizationType : Organization
{
//
}
In regards to your specific question inheritance vs. composition: The maxim i've heard over and over again is "use inheritance when object A is a type of object B. Use composition when object A is made up of object B".
In this case, you can't say that a regional office is a type of head office. Nor can you say that a head office is made up of regional offices. This tells me that the objects should not be directly related. Instead, think about what it is about each that makes them eligable to perform common tasks. Maybe they can both HireWorker because they are both HiringOrganizations, maybe they can both ReportSales because they are both SalesEntities. In these cases, you should have a HiringOrginization or SalesEntity superclass, of which both HeadOffice and RegionalOffice are subclasses.
As far as org structure goes, it might be worth considering to maintain that structure in a separate OrgStructure object. Instead of having a Parent attribute and a Child attribute in each object, your OrgStructure object would maintain the relationships between all of the object instances. This provides a bit more flexibility, and removes the responsibility of maintaining relationships into a dedicated object.
Take the following example code:
public abstract class ElementBase
{
}
public class ElementOne : ElementBase
{
}
public class ElementTwo : ElementBase
{
[XmlElement("element-one", typeof(ElementOne))]
[XmlElement("element-two", typeof(ElementTwo))]
public ElementBase[] SubElements { get; set; }
}
[XmlRoot("root-element")]
public class RootElement
{
[XmlElement("element-one", typeof(ElementOne))]
[XmlElement("element-two", typeof(ElementTwo))]
public ElementBase[] SubElements { get; set;}
}
The attributes on ElementOne.SubElements and ElementTwo.SubElements need to stay in sync (i.e., attributes added to one will need to be added to the other, and arguments need to stay the same), The reason for this is that in the xml, <element-one> and elements can both appear as subelements to <root-element> and <element-two>. The elements can be in any order, and the order is important. Also, there will probably be more subelements in the future. The way it is currently coded will make maintenance tedious and error-prone because of the need to maintain two separate places for attributes.
Is there a way to have these attributes "shared" between the two properties, such that a single edit will affect them both? I tried the following:
public class CommomAttribute : Attribute
{
public XmlElementAttribute f = new XmlElementAttribute("element-one", typeof(ElementOne));
public XmlElementAttribute l = new XmlElementAttribute("element-two", typeof(ElementTwo));
}
I then replaced the redundant attributes on the above classes' properties with a single [Command]. This didn't work.
An alternative question: is there a more elegant way to solve this problem?
You can try this if you don't mind having to go one level deeper to get to you sub-element items:
public abstract class ElementBase
{
}
public class ElementOne : ElementBase
{
}
public class ElementTwo : ElementBase
{
public SubElementList SubElements { get; set; }
}
public class SubElementList
{
[XmlElement("element-one", typeof(ElementOne))]
[XmlElement("element-two", typeof(ElementTwo))]
public ElementBase[] Items { get; set; }
}
[XmlRoot("root-element")]
public class RootElement
{
public SubElementList SubElements { get; set; }
}
Off the top of my head, I'd do the following:
On the ctor of each class (One and Two), require and instance of ElementBase and keep it as a private attribute (let's say, "SyncingElement")
Modify the setter of SubElements, to sync with the instance of "SyncingElement"
This way, SubElements on both objects would have the same memory address (same instance). So, if someone get the instance of SubElements from One modifies the object at index [2] (for example), it would affect SubElements at Two as well.
I'm having a hard time finding a clear-cut answer. My understanding from the docs is that ProtoInclude and ProtoMember tags within a class need
to be unique, but not across the whole tree.
Meaning this should be fine:
[ProtoContract]
[ProtoInclude(2, typeof(Employee))]
public class Person{
[ProtoMember(1)]
public string Name { get; set; }
}
[ProtoContract]
public class Employee : Person{
[ProtoMember(1)]
public string Department{ get; set; }
}
Is this correct?
If so, what happens when serialized properties are overridden?
Thanks a lot.
do tags have to be unique across the entire inheritance tree?
No they do not. Your understanding is correct. protobuf-net implements inheritance as a shim via encapsulation of derived types, so the restriction is simply that the tags for the sub-types must not conflict with any other tags inside that local type. So:
// this contract is an INVALID example
[ProtoContract]
[ProtoInclude(1, typeof(Employee))]
public class Person{
[ProtoMember(1)]
public string Name { get; set; }
}
is invalid, as the tags of the sub-type Employee and the property Name conflict.
Outside of that type there is no conflict. Other types can use "sub-type 1" and other types can use "property 1", etc.