I have some abstract base classes to be used on multiple implementations.
Base classes:
public abstract class BaseX
{
public string A { get; set; }
}
public abstract class BaseY : BaseX
{
public string B { get; set; }
}
For each use case, I want to create from these base classes specific classes like:
public abstract SpecificX : BaseX
{
public string C { get; set; }
}
public abstract SpecificY : BaseY
{
public string D { get; set; }
}
All classes that derive from SpecificY should contain all the properties A, B, C, D.
My problem now is, that SpecificY doesn't have the property C from SpecificX, because I cannot do multiple inheritance like
public abstract SpecificY : BaseY, SpecificX
My only idea would be to use Interface like this:
public Interface ISpecificX
{
string C { get; set; }
}
public abstract SpecificX : BaseX, ISpecificX
{
public string C { get; set; }
}
public abstract SpecificY : BaseY, ISpecificY
{
public string D { get; set; }
public string C { get; set; } <== redundancy
}
But then I'd need to implement C twice. And as soon as C is becoming more than a simple Property, things get ugly. Is there a better way to create this structure?
Thanks in advance,
Frank
I would strongly suggest to favour composition over inhertiance - as propsed by the GoF. This way you do not inherit a given class, but just use an instance of it. Then you can easily have all your properties without any duplication:
class BaseX { ... }
class BaseY { ... }
class SpecificY : BaseY
{
private readonly SpecificX b = new SpecificX();
public string A { get => this.b.A; set => this.b.A = value; } // delegate the call
public string B { get; set; }
public string C { get => this.b.C; set => this.b.C = value; } // delegate the call
public string D { get; set; }
}
Related
I have the following construction of classes, here simplified as child classes of a 'mother' class called DataClass, which also contains one simple method:
public class DataClass
{
public int num { get; set; }
public string code { get; set; }
public PartClass part { get; set; }
public MemberClass member { get; set; }
public int Count()
{
Type t = typeof(DataClass);
return typeof(DataClass).GetProperties().Length;
}
}
public class PartClass
{
public int seriesNum { get; set; }
public string seriesCode { get; set; }
}
public class MemberClass
{
public int versionNum { get; set; }
public SideClass side { get; set; }
}
public class SideClass
{
public string firstDetail { get; set; }
public string secondDetail { get; set; }
public bool include { get; set; }
}
The issue is, I want to refactor the method so that it can give me an accurate counting of all properties found, including the ones in nested or child classes. In the above example, it only counts properties of DataClass, while I wanted it to return 2 for DataClass + 2 for PartClass + 1 for MemberClass + 3 for SideClass, sums up to 8 properties you may set through DataClass.
Can someone help me with this?
You can introduce interface with Count() method
public interface ICountable
{
int Count();
}
And use this interface to mark all types, which properties are participating in Count() calculation.
You can see the generic abstract class to implement this interface below. Generic T parameter is type whose properties need to be calculated. You implement a calculation logic only once and inherit this class where needed. You also go through all of properties, implementing ICountable, to calculate them as well (some kind of recursion)
public abstract class Countable<T> : ICountable
{
public int Count()
{
Type t = typeof(T);
var properties = t.GetProperties();
var countable = properties.Select(p => p.PropertyType).Where(p => typeof(ICountable).IsAssignableFrom(p));
var sum = countable.Sum(c => c.GetProperties().Length);
return properties.Length + sum;
}
}
and inherit it in your classes
public class DataClass : Countable<DataClass>
{
...
}
public class PartClass : Countable<PartClass>
{
...
}
public class MemberClass : Countable<MemberClass>
{
...
}
public class SideClass : Countable<SideClass>
{
...
}
And this is for the test
var dataClass = new DataClass();
var count = dataClass.Count();
It returns 8 as expected
Say I have a class like...
public abstract class Base
{
public abstract IAttributes Attributes{ get; set; }
}
public interface IAttributes
{
string GlobalId { get; set; }
}
And a class like this...
public class ImplementAttributes : IAttributes
{
public string GlobalId { get; set; } = "";
public string LocalId { get; set; } = "";
// Other Properties and Methods....
}
And then I implement it like...
public class Derived: Base
{
public new ImplementAttributes Attributes { get; set; }
}
Now, I realise the above will not work because I can't override the property Attributes and if I hide it with new then the following bellow is null because the Base property does not get written.
public void DoSomethingWithAttributes(Base base)
{
var Foo = FindFoo(base.Attributes.GlobalId); // Null because its hidden
}
But I would like to be able to access the Base and Derived property attributes eventually like Above.
Can this be accomplished? Is there a better way?
You can use generics:
public abstract class Base<T> where T: IAttributes
{
public abstract T Attributes{ get; set; }
}
public interface IAttributes
{
string GlobalId { get; set; }
}
And
public class Derived: Base<ImplementAttributes>
{
public override ImplementAttributes Attributes { get; set; }
}
And then:
public void DoSomethingWithAttributes<T>(Base<T> b) where T : IAttributes
{
var Foo = FindFoo(b.Attributes.GlobalId);
}
You can pass Derived instances without specifying a type parameter explicitly:
Derived d = new Derived();
DoSomethingWithAttributes(d);
Let's say I have nested generic data classes similar to the following:
public class BaseRecordList<TRecord, TUserInfo>
where TRecord : BaseRecord<TUserInfo>
where TUserInfo : BaseUserInfo
{
public virtual IList<TRecord> Records { get; set; }
public virtual int Limit { get; set; }
}
public class BaseRecord<TUserInfo>
where TUserInfo : BaseUserInfo
{
public virtual DateTime CreationTime { get; set; }
public virtual TUserInfo UserInfo { get; set; }
}
public class BaseUserInfo
{
public virtual string Name { get; set; }
public virtual int Age { get; set; }
}
With 2 concrete versions like so:
// Project 1: Requires some extra properties
public class Project1RecordList : BaseRecordList<Project1Record, Project1UserInfo> {}
public class Project1Record : BaseRecord<Project1UserInfo>
{
public Guid Version { get; set; }
}
public class Project1UserInfo : BaseUserInfo
{
public string FavouriteFood { get; set; }
}
and
// Project 2: Some properties need alternate names for JSON serialization
public class Project2RecordList : BaseRecordList<Project2Record, Project2UserInfo>
{
[JsonProperty("allRecords")]
public override IList<Project2Record> Records { get; set; }
}
public class Project2Record : BaseRecord<Project2UserInfo> {}
public class Project2UserInfo : BaseUserInfo
{
[JsonProperty("username")]
public override string Name { get; set; }
}
I'm then happy to have 2 repositories that return Project1RecordList and Project2RecordList respectively, but at some point in my code I find myself needing to be able to handle both of these in one place. I figure that at this point I need to be able to treat both of these types as
BaseRecordList<BaseRecord<BaseUserInfo>, BaseUserInfo>
as this is the minimum required to meet the generic constraints, but trying to cast or use "as" throws up errors about not being able to convert.
Is there any way to do this, or even a more sane way to handle this situation without massive amounts of code duplication? If it makes any difference this is for a web app and there are already a large number of data classes, many of which use these nested generics.
What you are talking about is called covariance and MSDN has a great article on this here: https://msdn.microsoft.com/en-us/library/dd799517(v=vs.110).aspx
First, create a new interface:
interface IBaseRecord<out TUserInfo>
where TUserInfo : BaseUserInfo
{
}
Have BaseRecord inherit from the new interface:
public class BaseRecord<TUserInfo> : IBaseRecord<TUserInfo>
where TUserInfo : BaseUserInfo
{
public virtual DateTime CreationTime { get; set; }
public virtual TUserInfo UserInfo { get; set; }
}
If done right, this should compile:
IBaseRecord<BaseUserInfo> project1 = new Project1Record();
IBaseRecord<BaseUserInfo> project2 = new Project2Record();
To expand this to the BaseRecordList, create IBaseRecordList:
interface IBaseRecordList<out TRecord, out TUserInfo>
where TRecord : IBaseRecord<TUserInfo>
where TUserInfo : BaseUserInfo
{
}
Have BaseRecordList inherit from that:
public class BaseRecordList<TRecord, TUserInfo> : IBaseRecordList<TRecord, TUserInfo>
And then use as such:
IBaseRecordList<IBaseRecord<BaseUserInfo>, BaseUserInfo> project1 = new Project1RecordList();
IBaseRecordList<IBaseRecord<BaseUserInfo>, BaseUserInfo> project2 = new Project2RecordList();
Once you have that setup, just add whatever properties or functions you need to use generically to the interfaces.
I have following classes under different namespaces. I mean, the same 3 classes exist under different namespaces.
public class A
{
public int a { get; set; }
}
public class B
{
public A objA { get; set; }
}
public class C
{
public List<B> listBinC { get; set; }
}
In order to utilize/operate between the objects of these classes I thought of writing an interface wrapper such as
public interface iA
{
int a { get; set; }
}
public interface iB<T> where T: iA
{
T objA { get; set; }
}
public interface iC<T> where T : iB<iA>
{
List<T> listBinC {get; set; }
}
After this I have changed my Class definitions to
public class A : iA
{
public int a { get; set; }
}
public class B : iB<A>
{
public A objA { get; set; }
}
class C : iC<B>
{
public List<B> listBinC { get; set; }
}
When Compiled I am getting the following Error
The type 'Example.B' cannot be used as type parameter 'T' in the generic type or method 'Example.iC<T>'.
There is no implicit reference conversion from 'Example.B' to 'Example.iB<Example.iA>'.
I cannot change my class structure as it is provided by different team. What is the right way to enforce the interface 'constraints' to resolve the error?
public interface iC<T, TI>
where T : iB<TI>
where TI : iA
{
List<T> listBinC {get; set; }
}
Here iA is pulled out as a separate generic parameter, so you can apply a constraint on it (for TI to be derived from iA) and then declare B like this:
class C : iC<B, A>
{
public List<B> listBinC { get; set; }
}
I have an application that has a concept of a Venue, a place where events happen. A Venue has many VenueParts. So, it looks like this:
public abstract class Venue
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<VenuePart> VenueParts { get; set; }
}
A Venue can be a GolfCourseVenue, which is a Venue that has a Slope and a specific kind of VenuePart called a HoleVenuePart:
public class GolfCourseVenue : Venue
{
public string Slope { get; set; }
public virtual ICollection<HoleVenuePart> Holes { get; set; }
}
In the future, there may also be other kinds of Venues that all inherit from Venue. They might add their own fields, and will always have VenueParts of their own specific type.
Here are the VenuePart classes:
public abstract class VenuePart
{
public int Id { get; set; }
public string Name { get; set; }
public abstract string NameDescriptor { get; }
}
public class HoleVenuePart : VenuePart
{
public override string NameDescriptor { get { return "Hole"; } }
public int Yardage { get; set; }
}
My declarations above seem wrong, because now I have a GolfCourseVenue with two collections, when really it should just have the one. I can't override it, because the type is different, right? When I run reports, I would like to refer to the classes generically, where I just spit out Venues and VenueParts. But, when I render forms and such, I would like to be specific.
I have a lot of relationships like this and am wondering what I am doing wrong. For example, I have an Order that has OrderItems, but also specific kinds of Orders that have specific kinds of OrderItems.
Update: I should note that these classes are Entity Framework Code-First entities. I was hoping this wouldn't matter, but I guess it might. I need to structure the classes in a way that Code-First can properly create tables. It doesn't look like Code-First can handle generics. Sorry this implementation detail is getting in the way of an elegant solution :/
Update 2: Someone linked to a search that pointed at Covariance and Contravariance, which seemed to be a way to constrain lists within subtypes to be of a given subtype themselves. That seems really promising, but the person deleted their answer! Does anyone have any information on how I may leverage these concepts?
Update 3: Removed the navigation properties that were in child objects, because it was confusing people and not helping to describe the problem.
Here's one possible option using generics:
public abstract class VenuePart
{
public abstract string NameDescriptor { get; }
}
public class HoleVenuePart : VenuePart
{
public string NameDescriptor { get{return "I'm a hole venue"; } }
}
public class Venue<T> where T : VenuePart
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Company Company { get; set; }
public virtual ICollection<T> VenueParts { get; set; }
}
public class GolfCourseVenue : Venue<HoleVenuePart>
{
}
Here GolfCourseVenue has the collection VenueParts, which can contain HoleVenueParts or super classes HoleVenueParts. Other specializations of Venue would restrict VenueParts to containing VenueParts specific to that venue.
A second possibility is pretty much as you had it
public abstract class VenuePart
{
public abstract string NameDescriptor { get; }
}
public class HoleVenuePart : VenuePart
{
public string NameDescriptor { get{return "I'm a hole venue"; } }
}
public class Venue
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Company Company { get; set; }
public virtual ICollection<VenuePart> VenueParts { get; set; }
}
public class GolfCourseVenue : Venue
{
}
Now GolfCourseVenue has the collection VenueParts, which can contain VenueParts or super classes VenueParts. Here all specializations of Venue can contain any type of VenuePart which may or may not be appropriate.
In answer to your comment about covariance, I would propose something like this:
public abstract class VenuePart
{
public abstract string NameDescriptor { get; }
}
public class HoleVenuePart : VenuePart
{
public override string NameDescriptor { get{return "I'm a hole venue"; } }
}
public abstract class Venue
{
public int Id { get; set; }
public string Name { get; set; }
public abstract ICollection<VenuePart> VenueParts { get; }
}
public class GolfCourseVenue : Venue
{
private ICollection<HoleVenuePart> _holeVenueParts;
public GolfCourseVenue(ICollection<HoleVenuePart> parts)
{
_holeVenueParts = parts;
}
public override ICollection<VenuePart> VenueParts
{
get
{
// Here we need to prevent clients adding
// new VenuePart to the VenueParts collection.
// They have to use Add(HoleVenuePart part).
// Unfortunately only interfaces are covariant not types.
return new ReadOnlyCollection<VenuePart>(
_holeVenueParts.OfType<VenuePart>().ToList());
}
}
public void Add(HoleVenuePart part) { _holeVenueParts.Add(part); }
}
I look forward to the advice of others - but my approach is to use generics in this case. With generics, your GolfCourseVenue's "parts" are strong typed!
...and as I type this everyone else is saying generics too. HOW DO YOU overstackers type so dang fast?!
Anyways, pretending I'm still first -
public class VenuePart
{
}
public class HoleVenuePart : VenuePart
{
}
public abstract class Venue<T> where T : VenuePart
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Company Company { get; set; }
public virtual ICollection<T> Parts { get; set; }
}
public class GolfCourseVenue : Venue<HoleVenuePart>
{
public string Slope { get; set; }
}
Also, as a 2nd option, you could use an interface too, so in case you didn't like the name Parts, you could call it Holes when the derived type is known to be a GolfCourse
public class VenuePart
{
}
public class HoleVenuePart : VenuePart
{
}
public interface IPartCollection<T> where T : VenuePart
{
ICollection<T> Parts { get; set; }
}
public abstract class Venue<T> : IPartCollection<T> where T : VenuePart
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Company Company { get; set; }
public virtual ICollection<T> Parts { get; set; }
}
public class GolfCourseVenue : Venue<HoleVenuePart>
{
public string Slope { get; set; }
ICollection<HoleVenuePart> IPartCollection<HoleVenuePart>.Parts { get { return base.Parts; } set { base.Parts = value; }}
public virtual ICollection<HoleVenuePart> Holes { get { return base.Parts; } set { base.Parts = value;}}
}
You can use Covariance
public abstract class Venue
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Company Company { get; set; }
public virtual IEnumerable<VenuePart> VenueParts { get; set; }
}
public class GolfCourseVenue : Venue
{
public string Slope { get; set; }
public GolfCourseVenue()
{
List<HoleVenuePart> HoleVenueParts = new List<HoleVenuePart>();
HoleVenueParts.Add(new HoleVenuePart());
VenueParts = HoleVenueParts;
}
}
Assuming HoleVenuePart is inherited from VenuePart
If you remove "set" portions of both collections than it will make more sense: base class provides "all parts" collection, while derived classes have filtered view in addition to base class one.
Note: Depending on your needs making GolfVenue to be specialization generic of Venue<VenuePart> may not work as Venue<Type1> and Venue<Type2> will not have any good base class to work with.
Consider using interfaces instead of base classes as it would allow more flexibility in implementation.
public interface IVenue
{
public int Id { get; }
public string Name { get; }
public virtual IEnumerabe<VenuePart> VenueParts { get; }
}
public interface IGolfCourse : IVenue
{
public virtual IEnumerabe<HoleVenuePart> Holes { get; }
}
Now you can use GolfCourse:Venue from other samples but since it implements interface you can handle it in gnereic way too:
class GolfCourse:Venue<HoleVenuePart>, IGolfCourse {
public virtual IEnumerabe<VenuePart> Holes{ get
{
return VenueParts.OfType<HoleVenuePart>();
}
}
}
class OtherPlace:Venue<VenuePart>, IVenue {...}
List<IVenue> = new List<IVenue> { new GolfCourse(), new OtherPlace() };
Nothe that GolfCourse and OtherPlace don't have common parent class (except object), so without interface you can't use them interchangebly.