Here's the simplest form of my question:
IApple requires, among other things, property Flavor
IToffeeApple also requires property Flavor
The problem is, I want IToffeeApple to implement IApple (public interface IToffeeApple : IApple), but they both have the same property requirement. This becomes a problem when, for 1 purpose I need a Collection of Sweets (only IToffeeApple) where IToffeeApple can also be recognised as IApple.
Is it ok to use the "new" keyword in my interface, so that any implementers have 2 Flavor properties?
Have I explained myself poorly? :\
edit: I have. The actual context is geometry:
ILine requires a Start and End point IPoint.
ICurve requires a Start and End point IControlPoint.
ICurve is just extra functionality on top of ILine, yet it means I want to return the Start and End as IControlPoint rather than IPoint, so I either implement both and have a return of both IControPoint and IPoint of Start and End, or I just ignore IPoint/ILine and throw DRY out the window.
This is an elaboration of David Culp's answer. It's quite long, so I'm not posting as a comment.
While the generic interface IList<TPoint> looks like a good solution, I would recommend to elaborate the semantics a bit further. Also, it's advisory to consider introducing both generic and non-generic versions of some interface (like IEnumerable plus IEnumerable<T>).
In your clarified example you should introduce a term describing a finite entity that has a starting and ending point. Generally a curve is not a line but a line is a curve. However, since your curve uses ControlPoints to describe its start and end, while the line uses plain Points instead, in your specific case a line is not a curve. Instead, both line and curve are something like a shape.
// this interface will denote any shape that has a starting and ending point
public interface IShape
{
IPoint Start { get; set; }
IPoint End { get; set; }
}
// this interface will allow for specialization of staring end ending points' type
public interface IShape<TPoint> : IShape
{
// note 'new' will be required here most probably, I didn't compile it
TPoint Start { get; set; }
TPoint End { get; set; }
}
// a line will be a shape descibed by a pair of points; for the sake of
public interface ILine : IShape<Point> { }
// a curve will be a shape described by a pair of control points
public interface ICurve : IShape<ControlPoint> { }
Then, the actual implementations of ILine and ICurve can use explicit implementations of the Start and End properties coming from the non-generic IShape interface. This will favor strongly-typed access to the delimiting points, while preserving the ability to work with them as with plain IShapes.
public class Curve : ICurve
{
public ControlPoint Start { get; set; }
public ControlPoint End { get; set; }
IShape.Start
{
get { return Start; }
set
{
if (!(value is ControlPoint)) ... some error handling ...;
Start = (ControlPoint)value;
}
}
IShape.End { ... similarly as IShape.Start ... }
}
public class Line : ILine { ... similarly as Curve ... }
Note that in respect to the possible error scenario shown above an improvement could be limiting IShapes properties to getters only. Or, the setter passing the value into the strongly-typed version of Start or End could do some kind of conversion of a point into a control point. The right solution is domain-specific of course.
Try something along the lines of:
interface IFlavor;
interface ISweets: IFlavor;
interface IApple: IFlavor;
interface IToffeeApple: IApple, ISweets;
IEnumerable<ISweets> can hold the IToffeeApple, but not IApple.
When there seems to be a need to 'replace' an inherited property for the inheritance make sense I generally look for one of two things. Either the inheritance is forced (a car and an apple both have a color, but are not often thought of as polymorphic), or the inheritance is deeper than it seemed at first glance.
If I understand the example well enough, deeper inheritance fits well enough.
To fit your new example:
public interface IPoint
{}
public interface IControlPoint : IPoint
{
// added functionality of IControlPoint
}
public interface ILine<TPoint>
where TPoint : IPoint
{
TPoint Start { get; set; }
TPoint End { get; set; }
}
public interface ICurve<TPoint> : ILine<TPoint>
where TPoint : IPoint
{
// added functionality of ICurve
}
I am making the assumption that IControlPoint implements IPoint, but it seemed reasonable.
Basically, generics takes care of ICurve needing an IControlPoint to work with, while ILine needs an IPoint.
No, you don’t need the new keyword to inherit a property from an interface in another interface:
public interface IApple
{
Flavor Flavor { get; }
}
public interface IToffeeApple : IApple
{
ICollection<Sweet> Sweets { get; }
}
public class MyToffeeApple : IToffeeApple
{
public Flavor Flavor { get { return Flavors.ToffeeFlavor; } }
public ICollection<Sweet> Sweets { get { return new Sweet[0]; } }
}
Works just fine. If this doesn’t answer your question, please edit the question to include detail that explains in what way the above is insufficient.
No, because IToffeeApple is only inheriting from IApple (it isn't implementing anything, it's an interface) and there's no conflict; just leave the Flavour property out so it inherits it from IApple.
This doesn't becomes a property with a collection that only has IToffeeApple, because there won't be any conflicting cases there either.
It could only really become a problem if something implemented both IToffeeApple, and either something else where flavour had a different type, or IQuark where flavour has a different meaning. In this case the class implementing them should implement on or both of the properties explicitly.
Related
I'm wondering if there is a way to constrain the implementations of a generic type by asking Not to implement a specific interface
Something like
public class PrivateGarage<TVehicle> where TVehicle : **not** Itruck
{
...
}
This might works but it's less elegant
public class PrivateGarage<TVehicle>
{
public PrivateGarage()
{
if(typeof(TVehicle) is Itruck)
{
throw new ArgumentException("Truck is not a valid type for private garage");
}
}
}
There is an approach you can take to solve this, but it only works well if there is only one discriminant to worry about.
Let's suppose the base interface is IVehicle:
public interface IVehicle
{
public void Park();
}
In your case, the discriminant is whether or not the vehicle can go in the garage, i.e., is it a "private vehicle"?
The following two interfaces can represent the discriminant:
public interface ICommercialVehicle: IVehicle
{
}
public interface IPrivateVehicle: IVehicle
{
}
Now you can represent a private garage by requiring IPrivateVehicle rather than IVehicle:
public class PrivateGarage<T> where T: IPrivateVehicle
{
readonly List<IPrivateVehicle> _vehicles = new();
public void Park(T vehicle)
{
_vehicles.Add(vehicle);
}
}
Suppose you also have a Truck type that does not inherit directly or indirectly from IPrivateVehicle. In that case if you try to create a PrivateGarage<Truck> you'll get a compile error.
This approach does not scale at all well, so it's probably better to take the approach of using properties and checking them at runtime.
A slightly different approach is to use interfaces as "Tags". I must stress that this is considered by many to be a bad design.
To do that you'd use an IPrivateVehicle tag as a kind of attribute.
Then the hierarchy would be like this:
public interface IVehicle
{
public void Park();
}
public interface IPrivateVehicle {} // Tag interface. Considered bad design.
public class PrivateGarage<T> where T: IPrivateVehicle, IVehicle
{
readonly List<IVehicle> _vehicles = new();
public void Park(T vehicle)
{
_vehicles.Add(vehicle);
}
}
public interface ICar: IVehicle, IPrivateVehicle
{
}
public interface ITruck : IVehicle
{
}
Then if you had concrete classes implementing ICar and ITruck called Car and Truck respectively:
var carGarage = new PrivateGarage<Car>(); // Compiles
var truckGarage = new PrivateGarage<Truck>(); // Does not compile.
An advantage of this approach is that you can use many tags.
An disadvantage of this approach is that you can use many tags. ;)
No, there isn't. The only way to specify constraints is inclusive. There is no way to exclude specific subtypes. See the documentation for the list of permitted types of constraints.
The reason, most likely, is such a constraint would break polymorphism. If it were possible, it would mean that instances of a specific descendant of the actual type parameter, and its all descendants would, could not be passed to the generic class.
A possible alternate way to impose such a constraint is to introduce properties at an IVehicle interface such as:
public interface IVehicle
{
bool CanCarryPassengers { get; }
bool CanCarryCargo { get; }
}
However, there's much more to check for a hypothetical PrivateGarage, so in the reality, the conditional to allow a particular vehicle in the garage would be much more complicated than a simple negative constraint.
No, there is no weay to exclude a type, constraints don't work that way.
A common solution would be to have an interface specifically for this, like IVehicleThatCanGoInGarage, which may itself also implement IVehicle
public interface IVehicleThatCanGoInGarage : IVehicle
{}
public class PrivateGarage<TVehicle> where TVehicle : IVehicleThatCanGoInGarage
{
...
}
Consider the following interfaces in C#:
public interface IUpgradeable
{
public void Upgrade();
}
public interface ISpeedUpgradeable : IUpgradeable
{
public int GetCurrentSpeed();
}
public interface IDamageUpgradeable : IUpgradeable
{
public float GetCurrentDamage();
}
And the following class that implements them:
public class SpaceShip : ISpeedUpgradeable, IDamageUpgradeable
{
public int GetCurrentSpeed()
{
return 0;
}
public float GetCurrentDamage()
{
return 0f;
}
public void Upgrade()
{
//Which Upgrade am I implementing? ISpeedUpgradeable? or IDamageUpgradeable?
}
}
Since both ISpeedUpgradeable and IDamageUpgradeable both extend IUpgradeable, shouldn't they both have implementations of Upgrade() each? or am I misunderstanding how inheritance in interfaces work?
There is only one meaning of IUpgradeable. The fact that multiple interfaces inherit it, and add meaning to themselves doesn't change the meaning of the original interface. Your class simply implements ISpeedUpgradeable, IDamageUpgradeable, and IUpgradeable: it doesn't implement a specific flavor of IUpgradeable.
The Upgrade() method should only mean what it means to the IUpgradeable interface. Think about your business model (or in this case probably a game model): is there an item floating around that "upgrades" anything upgradeable that it comes in contact with? Does upgrading the ship mean upgrading its speed, or damage, or both? If simply calling Upgrade doesn't provide enough information to match the way your business model works, you may need to re-think your interface design.
I'm starting to see this pattern appear often in my code:
class Foo { }
interface IBar
{
Foo Foo { get; }
}
class Bar<TFoo> : IBar where TFoo : Foo
{
public TFoo Foo { get; private set; }
Foo IBar.Foo
{
get
{
return Foo;
}
}
}
Some of its benefits are:
An easy way to check whether an object is of the wrapping type (if (something is IBar))
Strong-typed access to TFoo in closed-constructed Bar<>s
Polymorphic access to Foo in interfaced IBars
One could argue that this kind of pattern is everywhere in the framework (e.g. List<T> : IList), but I wonder if this is just a remnant of .NET 1.0, when generics didn't exist.
Off the top of my head, my main concern is that IBar is not necessarily a proper contract that defines what members a "bar" should provide; it's only a hack to access generically typed members.
Also, if I start adding interfaces for that purpose, I quickly end up with hard to maintain parallel inheritance hierarchies.
Should I be worried about spreading this pattern in my code base? If so, what alternative patterns would provide some or all of the 3 benefits listed above?
Because explicitly implementing abstract members is not allowed, this "ideal" solution is not possible:
class Foo { }
class Bar
{
public abstract Foo Foo { get; }
}
class Bar<TFoo> : Bar where TFoo : Foo
{
private TFoo foo;
Foo Bar.Foo
{
get
{
return foo;
}
}
public new TFoo Foo
{
get
{
return foo;
}
}
}
For me, the summary is you shouldn't think that you implement interfaces just for the sake of augmenting a generic type parameter with more typing.
AFAIK, you use interfaces to provide which are the contracts to work with a given API. Generics are just a language feature/tool to provide more typing where you would end up doing a lot of casts. Hereby, with generics you limit your API to expect arguments implementing one or more interfaces and also with some requirements using generic constraints.
For example, if you just want to accept implementations of given interface called IWhatever, would you use generics?
public void DoStuff<T>(T whatever)
where T : IWhatever
{
}
// versus
public void DoStuff(IWhatever whatever)
{
}
BTW, without generics, how you would check that an implementation to IWhatever is a class and has a public constructor? You would end up with reflection and you're code would smell compared to using generics:
public void DoStuff<T>()
where T : class, IWhatever, new()
{
}
In fact, a generic parameter can constraint that T must inherit a given class and implement one or more interfaces:
public void DoStuff<T>(T arg)
where T : A, IEquatable<T>, IWhatever, IWhichever, IWherever
{
}
And whether if T inherits a type with or without generic parameters or implements interfaces with or without generic parameters, it's not a good or bad design per se but, again, just a language tool that's suitable to specific cases.
Therefore, your statement...
Off the top of my head, my main concern is that IBar is not
necessarily a proper contract that defines what members a "bar" should
provide; it's only a hack to access generically typed members.
...describes a particular design flaw instead of an actual problem with typing generics using the wonders of interfaces.
Conclusion: if IBar isn't a proper contract, then you should revisit your architecture and re-think your solution.
More background on the topic
Actually I thought that my original answer implied that I found the whole solution has a design flaw.
In summary, you're using interfaces to expose an association on certain classes which provide the type of the whole association using a generic type parameter. And you argue that you do this to be able to access such association in a less typed context:
However, I sometime need a "less" typesafe context, hence my question.
And then it's when covariance enters in action! See the following code sample:
public class SuperClass
{
}
public interface IWhatever<out TAssociation>
where TAssociation : SuperClass
{
TAssociation Association { get; }
}
public class SomeImplementation<TAssociation> : IWhatever<TAssociation>
where TAssociation : SuperClass
{
public TAssociation Association { get; set; }
}
Now let's define a derived class of SuperClass:
public class DerivedClass : SuperClass
{
}
And see how this works like a charm:
SomeImplementation<DerivedClass> someImpl = new SomeImplementation<DerivedClass>();
// Covariance: you decide the degree of specialization of TAssociation
// interfaces' type parameter. In our case, we'll upcast TAssociation to
// the SuperClass type.
IWhatever<SuperClass> whatever = someImpl;
Clearly this is the way to go since C# 4.0.
I would say that the right way of expressing your requirement is you need a less specialized context instead of a less typed context. Covariance/contravariance is one of the most powerful features available in C# to cover this scenario when generics are involved in the equation.
This practice isn't a code smell per se. In my case, I go for it when I really need to access one or more associations somewhere where I just need to access certain members with a concrete purpose.
For example, if I'm building a tree-style hierarchy, I would define an interface like this:
public interface IHasParent<out TParent>
{
TParent Parent { get; }
}
Which enables me to do this:
IHasParent<object> withParent = someObject as IHasParent<object>;
if(withParent != null)
{
// Do stuff here if some given object has a parent object
}
But I don't create interfaces indiscriminately because some day I'll need less typed access to some properties. There should be a well defined purpose. Otherwise, you can end up turning a nice solution into a code smell.
You would say don't repeat yourself but I still feel that there's no definitive answer without analyzing your project code base and checking how you really use this kind of interfaces to solve concrete problems.
So, strictly talking, if you use the whole pattern when it's really required, it should be a good design decision.
Maybe you want to avoid the unavoidable
Based on some chat we've had both the OP and me, I feel that the best conclusion is that the OP wants to avoid the unaviodable.
In an object-oriented language like C# interfaces are the right tool to both define type contracts and expose a subset of a full type implementing some interface.
Also, the OP would love a feature in C# like protocols where a class that implicitly fullfils an interface is enough to consider that it implements the interface which would save up many code lines if C# could have this feature:
public interface IWhatever
{
void DoStuff();
}
public class X
{
void DoStuff();
}
public class Y
{
public void HandleStuff(IWhatever whateverImpls)
{
}
}
Y y = new Y();
// Protocols would support passing an instance of X which may not implement
// IWhatever but it implicitly fulfills IWhatever:
y.HandleStuff(new X());
BTW, C# lacks this feature. Therefore, it's a waste of time scratching your head thinking how sweet would be having such feature. You need to deal with what C# has to offer already.
Anyway, if you just need to expose some associations across your object graph and get them selectively, you can use the wonders of interfaces using a more simplified approach than yours. Did you know that you can explicitly implement the same interface more than once if its generic arguments vary?
Why don't you design an interface like this:
public interface IHasAssociation<out TAssociation>
{
TAssociation Association
{
get;
}
}
public interface IHasManyAssociation<out TEnumerable, out TAssociation>
where TEnumerable : IEnumerable<TAssociation>
where TAssociation : Entity
{
TEnumerable Association
{
get;
}
}
public class Entity
{
}
public class Company : Entity
{
}
public class CustomerProfile : Entity
{
}
public class Contact : Entity
{
}
public class Customer :
IHasAssociation<Company>,
IHasAssociation<CustomerProfile>,
IHasManyAssociation<IList<Contact>, Contact>
{
public Company Company
{
get;
set;
}
public CustomerProfile Profile
{
get;
set;
}
public IList<Contact> Contacts
{
get;
set;
}
Company IHasAssociation<Company>.Association => Company;
CustomerProfile IHasAssociation<CustomerProfile>.Association => Profile;
IList<Contact> IHasManyAssociation<IList<Contact>, Contact>.Association => Contacts;
}
Definitively this keep things simpler (KISS!) because you don't need a parallel interface object graph definition, you simply define an interface to being able to get an association of a given type:
var customer = new Customer();
customer.Profile = new CustomerProfile();
customer.Company = new Company();
customer.Contacts = new List<Contact>();
var withCompany = customer as IHasAssociation<Company>;
var withCustomerProfile = customer as IHasAssociation<CustomerProfile>;
var withContacts = customer as IHasManyAssociation<IList<Contact>, Contact>;
if (withCompany != null)
{
Company company = withCompany.Association;
Console.WriteLine("This object has an associated company!");
}
if (withCustomerProfile != null)
{
CustomerProfile profile = withCustomerProfile.Association;
Console.WriteLine("This object has a profile!");
}
if (withContacts != null)
{
IList<Contact> contacts = withContacts.Association;
Console.WriteLine("This object has contacts!");
}
Also, see covariance in action:
if(customer is IHasManyAssociation<IEnumerable<Contact>, Contact>)
{
Console.WriteLine("This object has an enumerable of contacts!");
}
Or here's how you would get all association values of an implementor of one or many IHasAssociation<out TAssociation> interface implementations:
var entityAssociations = typeof(Customer)
.GetInterfaces()
.Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IHasAssociation<>))
.Select(i => i.GetProperty("Association").GetValue(customer));
foreach(var entityAssociation in entityAssociations)
{
Console.WriteLine($"{entityAssociation.GetType().FullName}");
}
This is the real beauty of generic programming! And remember: you won't need to implement IHasAssociation<out TAssociation>/IHasManyAssociation<out TEnumerable, out TAssociation> indiscriminately. That is, you implement on the classes to which associations need to be extracted in some place where you don't care who's the concrete owner of the association and you just need the association itself.
In your question, you express the need for a "generic" wrapper type (note I use the term "generic" here independently of any language).
Well, I don't see any problem with that. And if you ask me how to do it with .NET, I would just design this, once for all types, going one step further from you:
interface IWrapper<T>
{
T BaseObject { get; }
}
Then, a wrapper class would simply be:
class Bar<TFoo> : IWrapper<TFoo> where TFoo : Foo
{
public TFoo BaseObject { get; private set; }
}
I could go further again and define the non generic one, because it's ofen desirable to have both, as it's sometimes hard to work with generic-only clases/interface with meta/reflection code (but this is really optional):
interface IWrapper
{
object BaseObject { get; }
}
If you do this, it could be natural to have IWrapper<T> derive from IWrapper, like this:
interface IWrapper<T> : IWrapper
{
new T BaseObject { get; }
}
And the class would be this:
class Bar<TFoo> : IWrapper<TFoo> where TFoo : Foo
{
public TFoo BaseObject { get; private set; }
object IWrapper.BaseObject => BaseObject;
}
PS: as a side note, you can have a look at WCF's ServiceModel ChannelFactory<T> class that has a combined generic/non generic hierarchy somewhat relevant with your question.
I've found myself in a similar place after developing an API.
I have some questions for you and no answers.
But once you can answer those questions, maybe you know a bit more about how to address this situation.
I wonder how many classes implement IBar.
Are there enough to justify it?
Is this an API and you expose it to client code?
In how many code points do you leverage the polymorphism of the interface?
Just maybe... those answers can make you question the interface's usefulness.
How many times does this structure emerge?
And are you sure it actually does?
I mean, you say you did this:
implement lots of code (A);
refactor it in one place to clean it up;
implement more code (B);
refactor it to clean it up;
notice that B looks similar to A;
implement more code (C);
refactor it to clean it up;
notice that C looks similar to B (by transitivity also to A);
repeat...
Did the structure REALLY emerge, or is it your thinking that mold the code always in the same way?
Which comes first?
the emergence;
the thinking.
This "rinse" and "repeat" approach may be good to start, but just maybe... you've grown out of this methodology and should approach another one:
First design, then implement.
Is this your case? Have you grown that much, that you can finally approach design before implementation?
There's a saying that may apply here:
When you have a hammer, everything looks like a nail.
But let's assume this is not your case.
You don't fall into thought cycles and the underlying problem REALLY has this structure, thus your code reflects the problem's structure.
If you really came up with the same thing multiple times, but it's the problem, not your mind playing tricks, then the following may be a good advice.
Stop coding for a day, and think about it away from keyboard.
Which parts are the same, which different?
Can't you implement this in an even MORE abstract way (actual pattern) into which you inject the specialized code?
Maybe, underlying it all, is a something as simple as a composite pattern, and you could just implement that once and for all, and then reuse it all over the place.
What happened to me was similar, and I ended up with a dependency injection, an abstract factory, an abstract implementation of the composite pattern and an information expert, which took a configuration file and assembled the final object graphs I needed.
It was an excellent, humbling lesson in patterns and architecture, but I regretted actually using it.
Writing the documentation was near impossible and futile.
The code became extremely difficult to follow.
I always had to look things up and rethink about how to use it correctly.
The end result was not that astonishing.
So, if you want to learn and exercise, don't ever stop!
But if you want to just get it done and move on, don't overthink it.
Simple is better!
You may be in a place where you try to perfect your code but actually don't need it.
You're not writing a new API for M$, are you?
Just take this advice:
In a year or two, you won't be able to understand your own code. You must document it, if you make it that complex. If you can't document it, you'll never reuse it. So you don't need this perfection, it will be throw-away code.
In other words:
The real value is not the code, but the documentation that accompanies it. Without documentation there will be no reuse..
In retrospect, I've learned that the correct term for what I want is return type covariance, which is unfortunately not supported in C#, because the language design team does not consider the benefits of implementing the feature outweigh the cost, even though it preserves type safety. (A proposal has been drafted and completed, but it seems to be abandoned).
With return type covariance, the example code could be written as:
class Foo { }
class Bar
{
public virtual Foo Foo { get; }
}
class Bar<TFoo> : Bar where TFoo : Foo
{
public override TFoo Foo { get; }
}
The workaround proposed by Eric Lippert in that linked question is:
class Foo { }
abstract class Bar
{
protected abstract Foo foo { get; }
public Foo Foo => foo;
}
class Bar<TFoo> : Bar where TFoo : Foo
{
protected override Foo foo => this.Foo;
public new TFoo Foo { get { ... } }
}
It has the downside of duplicating not the inheritance hierarchy, but every covariant-simulated property per level of inheritance!
For further reading on how much clutter simulating covariant return types can bring to your code, consider that implementing ICloneable properly implies adding another virtual method per level of inheritance. I'll leave this as my humble plea for that language feature.
Can someone explain the exact use of interfaces in C#?
Has msdn not been helpful on this?
http://msdn.microsoft.com/en-us/library/87d83y5b.aspx
This has been discussed so many times here in the past that it is hard to pick any one duplicate for this question.
To save the time of repeating what has been said before, try this search, and start going through the results.
Imagine the the situation of having a factory that creates cars. You know that every vehicle has an engine and can be started, so you have the following:
interface IVehicle
{
Engine vehicleEngine { get; set; }
bool StartEngine();
}
Now, the factory makes an array of other vehicles, so for instance a truck and a normal car:
public Car : IVehicle
{
// MUST implement vehicleEngine and StartEngine:
public Engine vehicleEngine { get; set; }
public bool StartEngine()
{
// Cars needs to do xyz to start
}
public int MaxNumberOfPassenger { get; set; } // Specific to Car
}
and then:
public Truck : IVehicle
{
// MUST implement vehicleEngine and StartEngine:
public Engine vehicleEngine { get; set; }
public bool StartEngine()
{
// Trucks needs to do abc to start
}
public int MaximumLoad { get; set; } // Specific to Truck
}
This therefore forces all vehicles to implement specific members to fall under the category of a vehicle, but then can also be specialized with their own distinct members.
In the most simple terms, an Interface expresses what one, or more classes can do, although the implimentation may vary across the various classes.
Polymorphism
You can use 2 classes that implement the same interface without having to know exactly which concrete class it is. It aids in keeping code loosely coupled.
An interface defines the minimum requirements that a class that can be instantiated must implement. It expresses this through methods.
For instance, an interface could define a function called Foo which takes an integer and returns a boolean:
public interface ICanFoo
{
bool Foo(int number);
}
Any class which implements this interface must also implement this method:
public class Fooable : ICanFoo
{
public bool Foo(int number)
{
// do something
}
}
The implementation within the method is up to the specific classes which are implementing the interface.
By using interfaces you no longer care about implementation are compile time, but rather specification. You can call it like this:
ICanFoo myFooable = ...
bool success = fooable.Foo(4);
The actual type of fooable can be any class that implements ICanFoo since you know that ICanFoo will always define a method implementation for the Foo method.
UPDATE:
So pretty much everyone here has told me that I just need to start all over again on how I designed my classes (thank you folks for your excellent answers by the way!). Taking the hint, I started doing extensive reading on the strategy pattern. I want to create behavior classes (or strategy classes) that inherit from an abstract base class or classes. The Candidate class would then have properties w/ the different abstract base class/classes as the Type for the behaviors or strategies. maybe something like this:
public abstract class SalaryStrategy {
public abstract decimal Salary { get; set; }
public abstract decimal Min { get; set; }
public abstract decimal Mid { get; set; }
public decimal CompaRatio {
get {
if (this.Mid == 0) { return 0; }
else { return this.Salary / this.Mid; }
}
}
}
public class InternalCurrentSalaryStrategy {
public override decimal Salary { get; set; }
public override decimal Min {
get { return this.Salary * .25m; }
set { }
}
public override decimal Mid { get; set; }
}
public class Candidate {
public int Id { get; set; }
public string Name { get; set; }
public SalaryStrategy CurrentSalaryStrategy { get; set; }
}
public static void Main(string[] args) {
var internal = new Candidate();
internal.CurrentSalaryStrategy = new InternalCurrentSalaryStrategy();
var internalElp = new Candidate();
internalElp.CurrentSalaryStrategy = new InternalCurrentSalaryStrategy();
var elp = new Candidate();
// elp.CurrentSalaryStrategy can stay null cause it's not used for elps
}
Any comments or suggestions?
ORIGINAL Question:
I am trying to learn and become more proficient at design patterns and principles. I have am currently working on a design for few classes that has stumped me. Here's a very condensed version of the code:
public class Candidate {
public int Id { get; set; }
public string Comments { get; set; }
// lots more properties and behaviors...
}
public class InternalCandidate : Candidate {
public decimal CurrentMid { get; set; }
public decimal CurrentMax {
get { return this.CurrentMin * 1.3m;
}
// lots more properties and behaviors...
}
public class EntryLevelCandidate : Candidate {
public string Gpa { get; set; }
// lots more properties and behaviors...
}
public class InternalEntryLevelCandidate /* what do I inherit here??? */ {
// needs all of the properties and behaviors of
// EntryLevelCandidate but also needs the CurrentMin and
// CurrentMax (and possibly more) in InternalCandidate
}
The InternalEntryLevelCandidate class is primarily an EntryLevelCandidate but needs to share some of the implementations of InternalCandidate. I say implementations because I don't want the implementations to be different or repeated, otherwise I would use an interface for common contracts and have concrete implementations in each class. Some of the implementations of the InternalCandidate properties and behaviors need to be common or shared. I have read about C++ and Ruby mixins, which seem to be something similar to what I want to do. I also read this interesting blog post that discusses an idea for a behavior type where a class would be able to inherit multiple behaviors while still maintaining a single "is a" relationship: http://www.deftflux.net/blog/post/A-good-design-for-multiple-implementation-inheritance.aspx. This seems to convey what I am wanting. Can anyone give me some direction on how I can accomplish this using good design practices?
Immutable data value classes. If any properties in your various Candidate subclasses represent some kind of meaningful data value, create an immutable class for it, with the behaviors you need. Each of your distinct Candidate subclasses can then use the data type, but your code is still encapsulated in the data classes.
Extension methods. These could be overloaded to work with any classes.
I'd avoid the decorator pattern and stick with compiled/reflectable functionality.
Composition. Develop the unique behaviors in separate classes right away, and build your Candidate classes around them, rather than writing unique behaviors in your Candidate classes and trying to pull out their functionality for use in related classes later.
Depending on how you use the classes, you could also implement and make use of explicit and implicit conversion operators to a related type, so instead of reimplementing interfaces (which you wanted to avoid), you could actually cast your object into the type/implementation you need for whatever purpose.
Another thing I just thought of, related to that last paragraph, is to have a leasing system, where your class spawns and object of the appropriate type, allows it to be manipulated, then consumes it later to assimilate the updated information.
Here's a scholarly paper on the subject that I think is pretty interesting (PDF link).
But, I think you are trying to impose business logic in your generalizations. You happen to know that an InternalCandidate will never have his GPA looked at. But, an InternalCandidate certainly has a GPA. So, you have cracked out this strange guy called an InternalEntryLevelCandidate because you happen to know that you want to look at this guy's GPA. Architecturally, I think the EntryLevelCandidate is incorrect. I would add a "Level" concept to a Candidate and give him a GPA. It's up to the business logic to decide if they look at the GPA or not.
Edit: Also, Scott Meyers does a great job of dissecting this issue in his books.
Disclaimer:
In my experience needing multiple inheritance is the exception rather than the rule, careful design of class hierarchies can usually avoid needing this feature. I agree with JP that this requirement could be avoided in your sample.
Back to the question, there is no clean solution, however you have a few options:
Use extension methods, has the disadvantage that right click Resolve does not works, also some people really dislike these puppies.
Create an aggregate object that holds and instance of each class you want composited, re-implement stub methods that delegate.
Define an interface for each behavior and have the methods in the base check if this is IInterface before executing the behavior. (allows you to pull behavior definitions to the base)
Near duplicate:
Multiple inheritance in C#
I agree that inheritance doesn't seem to be the right thing here. I'm not sure that I know the perfect answer, but perhaps the Decorator pattern is appropriate.
Another, more esoteric idea is to think about aspect-oriented programming. You can do some pretty amazing things with aspects, but it's a very advanced topic that I still haven't mastered. The kind of folks who have are like Rikard Oberg and his Qi4J cohorts.
I'd just use the Delegation pattern. Ultimately I'd use an interface for each distinct piece of functionality, then have a concrete class as a delegate for each interface. Then your final classes just use the delegates they need and can inherit from multiple interfaces.
public class InternalEntryLevelCandidate : EntryLevelCandidate {
private InternalCandidate internalCandidateDelegate
= new InternalCandidate();
public decimal CurrentMid {
get { return internalCandidateDelegate.CurrentMid; }
set { internalCandidateDelegate.CurrentMid = value; }
}
public decimal CurrentMax {
get { return internalCandidateDelegate.CurrentMax }
}
}