I have 2 sets of 2 classes where each pair has a super/sub-class relationship, and the orthogonal pair has a dependency relationship. What I am trying to determine is what to do with the constructors and/or bodies of the properties to keep the model as simple as possible with minimal data duplication.
Here's the structure in code:
public class Base1 {
public List<Base2> MyBase2Things { get; set; }
// Do things with Base2 objects
}
public class Sub1 : Base1 {
public List<Sub2> MySub2Things { get; set; }
// Do things with Sub2 objects and also with Base2 objects
}
public class Base2 {
public Base1 MyBase1 { get; set; }
// Do things with the Base1 object
}
public class Sub2 : Base2 {
public Sub1 MySub1 { get; set; }
// Do things with the Sub1 object
}
I have considered overriding the base properties in the sub-classes, but that doesn't fit very cleanly because the properties in the sub-classes don't have the same signature and so I would have to add properties.
I have also considered setting the base property in the sub-class constructor and set methods, but there is no way for the sub-class property to be updated if the base-class's property is updated.
What other options are there, and which is the cleanest (and why)?
Note: The above code is greatly simplified to illustrate the problem. There are additional properties and methods on the real classes, but this subset is the essence of the trouble I'm having.
I agree with Yaur that generics may help. As far as your options and keeping the model simple as possible - this probably depends on the specifics like the responsibilities of your 4 classes.
Let's say you're dealing with parent/child relationships of various vehicles & vehicle parts.
Scenario 1: The inherited relationship brings in orthogonal capability.
public class ItemParent { // formerly Base1
public List<ItemChild> MyChildren {get; set;}
}
public class ItemChild { // formerly Base2
public ItemParent MyParent {get; set;}
}
public class Car : ItemParent { // formerly Sub1
public List<CarPart> MyParts {get; set;}
}
public class CarPart : ItemChild { // formerly Sub2
public Car ParentCar {get; set;}
}
Of course, Cars should specifically know about CarPart, not ItemChild. So you fall back on generics here.
public class ItemParent<T> where T : ItemChild {
public List<T> MyChildren {get; set;}
}
public class ItemChild<T> where T : ItemParent {
public T MyParent {get; set;}
}
public class Car : ItemParent<CarPart> {}
public class CarPart : ItemChild<Car> {}
public class Truck : ItemParent<TruckPart> {}
public class TruckPart : ItemChild<Truck> {}
You can call subclass.MyChildren[] just fine, or make a MyParts property which delegates to MyChildren.
In this example, I think the model is pretty simple due to the fact that the parent/child metaphor is pretty easy to grok. Plus, if you add Truck-TruckParts (or Household-Resident, Shape-Line, etc.) you're not really increasing the complexity.
An alternative here would be to move the parent/child "responsibility" to a collection object (possibly custom), like so:
public class ParentChildCollection<TParent, TChild> {}
public class Car {
private ParentChildCollection<Car, CarPart> PartHierarchy;
public List<CarPart> MyParts {get { return PartHierarchy.GetMyChildren(this); } }
}
public class CarPart {
private ParentChildCollection<Car, CarPart> PartHierarcy;
public Car ParentCar {get { return PartHierarchy.GetMyParent(this); }}
}
The downside here is that, while clean, Truck and Car might not share a lot of code (if that's what you were wanting).
Scenario 2: The inherited relationship is about specializing to a parallel item.
public class Car { // formerly Base1
public List<CarPart> MyParts {get; set;}
}
public class CarPart { // formerly Base2
public Car MyParent {get; set;}
}
public class Truck : Car { // formerly Sub1
public List<TruckPart> MyParts {get; set;}
}
public class TruckPart : CarPart { // formerly Sub2
public Truck MyParent {get; set;}
}
In this case, Truck and Car do share more code. But this starts running into signature problems that aren't easily solved even with generics. Here, I'd consider making the base class more generic (Vehicle-VehiclePart). Or consider refactoring this second scenario into the first scenario. Or use the collection for parent/child management and the inheritance stictly for Car-Truck code consolidation.
At any rate, I'm not really sure that either scenario matches your case. At least some factor are based on how you have (and how you can) arrange your relationships.
Generics may be able to help you with at least part of this... something like:
public class Base1<T>
where T: Base2
{
public List<T> MyThings { get; set; }
protected Base1(List<T> listOfThings)
{
this.MyThings = listOfThings;
}
}
public class Sub1 : Base1<Sub2>
{
public Sub1(List<Sub2> listofThings):
base(listofThings)
{
}
}
making it work where you need to subclass in both directions can get tricky (and messy) quickly, but will look something like:
// Base 1 hierachy
abstract public class Base1
{
protected abstract Base2 GetBase2(int index); //we can't return the list directly
}
public class Base1<Base2Type> :Base1
where Base2Type : Base2
{
public List<Base2Type> MyBase2s { get; set; }
protected Base1(List<Base2Type> listOfThings)
{
this.MyBase2s = listOfThings;
}
protected override Base2 GetBase2(int index)
{
return MyBase2s[index];
}
}
public class Sub1<MySub1Type,MySub2Type> : Base1<MySub2Type>
where MySub1Type : Sub1<MySub1Type,MySub2Type>
where MySub2Type : Sub2<MySub1Type, MySub2Type>
{
public Sub1(List<MySub2Type> listOfThings):
base(listOfThings)
{
this.MyBase2s = listOfThings;
}
}
public class Sub1 : Sub1<Sub1,Sub2>
{
public Sub1(List<Sub2> listofThings):
base(listofThings)
{
}
}
// base 2 hirachy
abstract public class Base2
{
protected abstract Base1 MyBase1 { get; }
}
public class Base2<Base1Type,Base2Type> : Base2
where Base1Type: Base1<Base2Type>
where Base2Type : Base2
{
public Base1Type myBase1;
protected override Base1 MyBase1{ get {return myBase1;} }
}
public class Sub2<Sub1Type, Sub2Type> : Base2<Sub1Type,Sub2Type>
where Sub1Type : Sub1<Sub1Type,Sub2Type>
where Sub2Type : Sub2<Sub1Type,Sub2Type>
{
}
public class Sub2 : Sub2<Sub1,Sub2>
{
}
Related
I have a base class and derived class. Derived class has same property as base class but it needs always return same value/readonly
public class BaseClass
{
public int Id {get; set;}
public TransactionTypeEnum TransactionType {get; set;}
}
public class DerivedClass: BaseClass
{
public new TransactionTypeEnum TransactionType {get;} = TransactionTypeEnum.Credit;
}
The problem with this is when I cast derived class to base I of course end up with 2 properties: one from base and one from derived. I could also declare TransactionType property as virtual and then override it in derived class but then I'm forced to add setter method. What's the best course of action in this case? Create a mapper between these 2 classes ?
From my perspective, your desire violates the Liskov substitution principle (see here): your base class defines a settable TransactionType. Since every derived class inherits that behavior, you either shouldn't break it or remove the behavior - i. e. remove the setter. Maybe the derived class isn't a real inheritor?
Another approach could look like this (protected setter):
public class BaseClass
{
public int Id {get; set;}
public TransactionTypeEnum TransactionType { get; protected set; }
}
public class DerivedClass: BaseClass
{
public DerivedClass()
{
TransactionType = TransactionTypeEnum.Credit;
}
}
you can make the property in the BaseClass virtual and then override it in the DerivedClass using a lambda expression to avoid the setter.
public class BaseClass
{
public int Id {get; set;}
public virtual TransactionTypeEnum TransactionType {get; set;}
}
public class DerivedClass: BaseClass
{
public override TransactionTypeEnum TransactionType => TransactionTypeEnum.Credit;
}
I have a base class for all the ENTITIES of my project which is inheriting from below model :
public class BaseModel
{
public int Id { get; set; }
public int CreatedDate { get; set; }
public override string ToString();
}
Now I have 1 another functionality which is common for so many modules and I want to keep BaseModel for that functionality and want it to be inherited from it.
Public class BaseNotice
{
// Common info related to notice which is use to send notice to employees in different scenarios
}
Now our every model is suppose to inherit from BaseModel so inheriting from BaseNotice will be multiple inheritance.
Now I cannot like below :
Public class BaseNotice : BaseModel
{
// Common info related to notice which is use to send notice to employees in different scenarios
}
Because I would like to control functionality related to Notice from BaseNotice model and for notice I would like to keep BaseNotice as base model.
But I am not getting how to avoid multiple inheritance here and so what would be the proper way to design this?
There is No need to Multiple Inheritance. you can do that in this way:
public class BaseModel
{
public int Id { get; set; }
public int CreatedDate { get; set; }
public override string ToString();
}
public interface IBaseNotice
{
// Base Notices Contracts should be placed here
}
Public class BaseNotice: IBaseNotice
{
// Common info related to notice which is use to send notice to employees in different scenarios
}
public class ModelX:BaseModel
{
public IBaseNotice Notice { get ; set; }
public ModelX(IBaseNotice baseNotice)
{
Notice = baseNotice;
}
}
Or you can use Second Generation of your BaseModel:
public class BaseModeNoticable:BaseModel
{
public IBaseNotice Notice { get ; set; }
public BaseModeNoticable(IBaseNotice baseNotice)
{
Notice = baseNotice;
}
}
It is clearly explained here how to achieve "multiple inheritance" in C# by using Interface. However, I wonder, how to achieve the same but in the Entity Framework Code First Workflow.
Provided code to make things clear :
public abstract class DomainObject {
// Every business model must have this fields
public Guid Id {get;set;}
public string SystemCode {get;set;}
}
And here also some optional abstract classes like:
public abstract class MultiTitleObject : DomainObject {
public string TitleRu { get; set; }
public string TitleEn { get; set; }
}
public abstract class ManageableByAdminObject : DomainObject {
public bool isVisibleOnSite {get;set;}
public bool isDeletedByAdmin {get;set;}
}
Let's say that I have class that need to have fields of both MultiTitleObject and ManageableByAdminObject and DomainObject as always rule.
Since C# doesn't support multiple inheritance, I can do the following :
public class ManageableByAdminDomainObject : ManageableByAdminObject {
}
public class ManageableByAdminMultiTitleDomainObject : ManageableByAdminDomainObject {
// Even here it's too complicated...
// What if I need to inherit from 3 or more classes?
}
So the solution I wanted to use is Interface like :
public interface IFieldImitation {
bool isVisibleOnSite ();
}
public class ManageableByAdminObject : IFieldImitation, DomainObject {
public bool isVisibleOnSite () => return true;
}
However, EF does understand abstract classes but not the interfaces.
How should I solve this problem?
Let's use a quite plain example with employees and company(-ies).
public abstract class Employee
{
// bunch of its features
}
public sealed class SalesManager : Employee
{
}
public sealed class SEO : Employee
{
}
Employee can take different posts or play different roles. So using inheritance (maybe with factory patterns in addition) doesn't give such a flexibility for concrete employee instance to change its role.
What would you advice, unfortunately I haven't seen the kind of approaches yet. And I haven't met a book which lights up the problem.
Edit
Thank you guys! In my edit I wanted to ask one more thing. Using generic role is it possible to transfer such a BLL to DAL. I have heard that generics are not supported in Entity Framework??
Thanks!
Use a has-a relationship
public class Employee
{
public Role EmployeeRole { get; set; }
}
public enum Role
{
SalesManager,
SalesPerson
}
Or you can make Role a class to store additional information in addition to the name of their role.
public class Role
{
public string Name { get; set; }
public decimal BaseSalary { get; set; }
}
To illustrate #Aasmund Eldhuset's comment:
public abstract class Role
{
public string Name { get; set; }
public decimal BaseSalary { get; set; }
public abstract void PerformRole();
}
public class SalesPerson : Role
{
public void PerformRole()
{
// Do something
}
}
Running with the idea of using a class, you can make it generic:
abstract class EmployeeRole { }
or
interface EmployeeRole { }
And have different types inherit from this abstraction:
class CEO : EmployeeRole { }
class SalesMgr : EmployeeRole { }
class Employee<T> where T : EmployeeRole
{
}
Then have a generic Factory implementation:
public Employee<T> MakeEmployee<T>() where T : EmployeeRole
{
}
I'm having trouble trying to implement a shared method/property between two classes created by the linq2sql designer.
My two classes have two main properties (coming from the db model):
public partial class DirectorPoll
{
public bool Completed {get; set;}
public bool? Reopen { get; set; }
//more properties
}
public partial class StudentPoll
{
public bool Completed {get; set;}
public bool? Reopen { get; set; }
//more properties
}
Now for example I create an abstract class:
public abstract class GenericPoll
{
public abstract bool Completed { get; set; }
public abstract bool? Reopen { get; set; }
public bool CanEdit
{
get
{
if (Completed == false) return true;
if (Reopen.GetValueOrDefault(false) == false) return false;
return true;
}
}
}
Then
public partial class DirectorPoll : GenericPoll
public partial class StudentPoll: GenericPoll
But when I try to compile it says "Director does not implement inherited abstract member GenericPoll.Completed.get". But it is there. So I think I'm forced to put an override to the property automatically generated by the designer, but if I update the database later and recompile it will give me the same error.
I think I might be missing something here but I've tried different approaches with no success. ¿So what can I do here, besides implementing CanEdit in each of my partial classes? Thanks
It isn't implemented as an override, so it doesn't count. However, implicit interface implementations do count, so this works:
partial class DirectorPoll : IGenericPoll {}
partial class StudentPoll : IGenericPoll {}
public interface IGenericPoll
{
bool Completed { get; set; }
bool? Reopen { get; set; }
}
public static class GenericPoll {
public static bool CanEdit(this IGenericPoll instance)
{
return !instance.Completed || instance.Reopen.GetValueOrDefault();
}
}
One option: create an interface containing Completed and Reopen, make the classes implement the interface (via the manual bits of the partial classes), then write an extension method which extends that interface. I think that should work:
public interface IPoll
{
bool Completed {get; set;}
bool? Reopen { get; set; }
}
// Actual implementations are in the generated classes;
// no need to provide any actual code. We're just telling the compiler
// that we happen to have noticed the two classes implement the interface
public partial class DirectorPoll : IPoll {}
public partial class StudentPoll : IPoll {}
// Any common behaviour can go in here.
public static class PollExtensions
{
public static bool CanEdit(this IPoll poll)
{
return !poll.Completed || poll.Reopen.GetValueOrDefault(false);
}
}
Admittedly then it has to be a method rather than a property, as there's no such thing as an extension property, but that's not too much of a hardship.
(I believe my refactoring of your logic in CanEdit is correct. All those explicit trues and falses were doing my head in ;)