Reputation: 15430
I have two classes one is derived from CheckBoxList and the second one from DropDownList. The code inside them is exactly the same. The only difference is that I need first one at places where I need to show checkboxlist and second one to show dropdownlist. Below is my code:
using System;
using System.Collections.ObjectModel;
using System.Web.UI.WebControls;
namespace Sample
{
public class MyCheckBoxList : CheckBoxList
{
public int A { get; set; }
public int B { get; set; }
protected override void OnLoad(EventArgs e)
{
//dummy task
Collection<int> ints = new Collection<int>();
//........
this.DataSource = ints;
this.DataBind();
}
}
}
The second one
using System;
using System.Collections.ObjectModel;
using System.Web.UI.WebControls;
namespace Sample
{
public class MyDropDownList : DropDownList
{
public int A { get; set; }
public int B { get; set; }
protected override void OnLoad(EventArgs e)
{
//dummy task
Collection<int> ints = new Collection<int>();
//........
this.DataSource = ints;
this.DataBind();
}
}
}
Now as you can see the internal code is exactly the same which I want to avoid. How can I make a common class for it so as to remove code duplicacy?
Upvotes: 6
Views: 1542
Reputation: 2503
You use composition, Make another class that is not related to these two classes, then have the common code in that one, when you need to use the code in either classes you make an instance, you can also use it thorugh an interface. No need to use inheritnece.
Update : Code Below ( Modified the code already provided by meziantou)
internal interface IEntity
{
int A { get; set; }
int B { get; set; }
Collection<int> GetCollection { get; }
}
internal class Entity : TrialBalanceHTMLToDataTable.TrialBalance.IEntity
{
public int A { get; set; }
public int B { get; set; }
public Collection<int> GetCollection
{
get{
//dummy task
Collection<int> ints = new Collection<int>();
//........
return ints;
}
}
}
public class MyDropDownList : DropDownList
{
public MyDropDownList() { _Entity = new Entity(); }
private IEntity _Entity { get; set; }
protected override void OnLoad(EventArgs e)
{
this.DataSource = _Entity.GetCollection;
this.DataBind();
}
}
Upvotes: 0
Reputation: 1769
It would seem that what you are trying to accomplish is to have a single class, that is MyDropDownList
, be able to inherit properties from the DropDownList
, and to have the MyCheckBox
class inherit properties from the CheckBox
class, while having your two My* classes have some extra properties, which happen to be identical.
As others have suggested, the easiest way to accomplish this would be through Multiple Inheritance. In your example specifically, that would mean creating a (possibly abstract) class that describes the shared attributes between MyDropDownList
and MyCheckBox
, and then have those two classes inherit from both their respective System.Web.UI.WebControls bases as well as this "shared" class. However, as it has been said, C# doesn't support multiple inheritance. From Chris Brumme via that link:
The number of places where MI is truly appropriate is actually quite small. In many cases, multiple interface inheritance can get the job done instead. In other cases, you may be able to use encapsulation and delegation.
You may have also considered using Interfaces. This, as you may have discovered, would be an inappropriate choice for your solution as an Interface only allows you to define that there are certain properties and methods in a class, but not how the properties or methods are defined. So again, this is an inappropriate choice for removing duplicate code.
What does this mean for you? Well, if you're looking to write a MyDropDownList
class that supports both myCustomDDLInstance.SelectedIndex
and myCustomDDLInstance.A
syntaxes, you will have to do a little bit of "magic". But the fact that your language doesn't support what you are trying to do should raise a red flag! It's not necessarily wrong, but it should be a strong indicator that you may want to reexamine your design.
My guess is that the duplicated part of the two classes can stand alone as it's own logical entity. This means that you can justifiably create your own class to hold these shared properties and methods. Here's what we get:
SampleControl.cs
public class SampleControl
{
public int A { get; set; }
public int B { get; set; }
public Collection<int> MysteryCollection
{
get
{
Collection<int> ints = new Collection<int>();
//........
return ints;
}
}
}
If CSharp did in-fact support multiple inheritance, your MyDropDownList
class could inherit from both DropDownList
and SampleControl
and you'd be done. But again, this isn't possible.
So how do we accomplish your goal? It's a bit convoluted, but you can Encapsulate your shared properties and methods in each of your custom classes. Here's an example for the MyDropDownList
class (note that MyCheckBoxList
would be the same, just change the class name:
public class MyDropDownList : DropDownList
{
private SampleControl mySampleControl { get; set; }
public int A
{
get
{
return mySampleControl.A;
}
set
{
mySampleControl.A = value;
}
}
public int B
{
get
{
return mySampleControl.B;
}
set
{
mySampleControl.B = value;
}
}
public MyDropDownList()
{
mySampleControl = new SampleControl();
}
protected override void OnLoad(EventArgs e)
{
//dummy task
this.DataSource = mySampleControl.MysteryCollection;
this.DataBind();
}
}
A class designed in this way, while a bit convoluted, should accomplish the type syntax that you are looking for.
As a final note I would strongly encourage you to at least consider re-examining your design and seeing if there is a better way for you to approach your class hierarchy. My recommendation is that if your shared attributes can exist on their own as a logical entity, they probably should be their own class. And if so, that class is probably a rightful and logical member of your MyDropDownList
and MyCheckBox
classes. Which means that you should be using the myDropDownListInstance.SharedAttributesClassName.A
syntax. It's both more explicit and more honest.
Upvotes: 0
Reputation: 10003
you can not, because c# does not support multiple inheritance of implementation (and you are already subclassing). you could refactor some of the code into a third class and have each of your classes have an instance and delegate calls to it.
you could try something like this: http://www.codeproject.com/KB/architecture/smip.aspx, but it looks like a lot of work.
Upvotes: 0
Reputation: 21337
You can create a third class
public class Entity
{
public int A { get; set; }
public int B { get; set; }
Collection<int> GetCollection()
{
//dummy task
Collection<int> ints = new Collection<int>();
//........
return ints;
}
}
And then use it in other classes
public class MyDropDownList : DropDownList
{
public MyDropDownList() { Entity = new Entity(); }
public Entity {get;set;}
protected override void OnLoad(EventArgs e)
{
this.DataSource = Entity.GetCollection();
this.DataBind();
}
}
Upvotes: 3