I have the following design goal in a class hierarchy:
There is a BaseClass defining some properties, which would usually be read/write:
public class Media
{
public virtual object Content { get; set; }
public virtual double recordingLength { get; set; }
}
The intention is to have some subclasses where this property now is readonly:
public class CompactDisk : Media
{
public override object Content
{
get { return this.getContent(); }
set {
// THERE SHOULDN'T BE A SETTER
}
}
public override double recordingLength
{
get { return 74; }
set {
// NO SETTER EITHER HERE!
}
}
}
I'm lost here, because I don't know how should I implement my design intent.
One possible approach is using interfaces.
You can split your base concept into two interfaces:
public interface IWritableMedia
{
object Content { set; }
double recordingLength { set; }
}
public interface IReadOnlyMedia
{
object Content { get; }
double recordingLength { get; }
}
And then something like CompactDisk should only implement IReadOnlyMedia:
public class CompactDisk : IReadOnlyMedia
{
public object Content { get { return ......; } }
public double recordingLength { get { return .......; } }
}
If you want to implement a CD-RW (rewritable), you should implement both interfaces:
public class RewritableCompactDisk : IReadOnlyMedia, IWritableMedia
{
public object Content { get; set; }
public double recordingLength { get; set; }
}
This way you can type your variables as IReadOnlyMedia or IWritableMedia:
IReadOnlyMedia media = new CompactDisk();
IWritableMedia media2 = new RewritableCompactDisk();
Now the issue is IWritableMedia doesn't provide getters and you don't want to declare another variable of type IReadOnlyMedia. The solution is designing a third interface called IReadWriteMedia and RewritableCompactDisk should implement it:
public interface IReadWriteMedia : IReadOnlyMedia, IWritableMedia
{
}
public class RewritableCompactDisk : IReadWriteMedia
{
public object Content { get; set; }
public double recordingLength { get; set; }
}
Since IReadWriteMedia implements IReadOnlyMedia and IWritableMedia, now you'll be able to type variables with IReadWriteMedia and access both getters and setters:
IReadWriteMedia media3 = new RewritableCompactDisk();
object content = media3.Content;
media3.Content = "hello world";
You can't, or really shouldn't, have a design where the sub types "hide" functionality of the base type. You can:
In your setters throw a NotSupportedException, or similar. This is how the Stream class behaves when you try to set the length of a stream that cannot be set.
Change your design. I don't see a way to get properties working the way you want (without resorting to "hiding", which IMHO isn't a good solution), but perhaps something like this:
public interface IMedia
{
object Content { get; }
double RecordingLength { get; }
}
public interface IWritableMedia : IMedia
{
void SetContent(object content);
void SetRecordingLength(double length);
}
Your CompactDisk would implement the just the IMedia interface, whereas a HardDrive class may choose to implement the IWritableMedia interface.
Related
I'm working on an abstract algebra library for C#, but am having trouble with implementing interfaces. I have gotten the implementation to work for certain groups, but attempting to create rings is giving me some serious problems. In particular, I've got the following:
public class Scaffolding {
public interface IMonoid<T> : ISemiGroup<T> {
T Identity { get; set; }
}
public interface IGroup<T> : IMonoid<T> {
T Inverse(T a);
}
public interface IRing<T> {
IGroup<T> AdditiveStructure { get; set; }
IMonoid<T> MultiplicativeStructure { get; set; }
}
}
public class ModularMonoid : Scaffolding.IMonoid<int> {
// Implements all necessary monoid properties
}
public class ModularGroup : Scaffolding.IGroup<int> {
// Implements all necessary group properties
}
public class ModularRing : Scaffolding.IRing<int> {
public ModularGroup AdditiveStructure { get; set; }
public ModularMonoid MultiplicativeStructure { get; set; }
// Implement ring-specific properties
}
I get an error stating that 'ModularRing' does not implement interface member 'Scaffolding.IRing.AdditiveStructure'. 'ModularRing.AdditiveStructure' cannot implement 'Scaffolding.IRing.AdditiveStructure' because it does not have the matching return type of 'Scaffolding.IGroup'. I get a similar error for the MultiplicativeStructure. This is strange to me, because both the ModularGroup and ModularMonoid implement IGroup and IMonoid respectively.
Yes, those classes implement the interfaces, but that interface doesn't say "The type of the AdditiveStructure property is something that implements IGroup<T>" - it says that the type of the AdditiveStructure property is IGroup<T>. To implement the interface, you have to match return types exactly.
If you want to be able to implement the interface like that, you'd need to change the interface, potentially like this:
public interface IRing<T, TGroup, TMonoid>
where TGroup : IGroup<T>
where TMonoid : IMonoid<T>
{
TGroup AdditiveStructure { get; set; }
TMonoid MultiplicativeStructure { get; set; }
}
Then implement it as:
public class ModularRing : Scaffolding.IRing<int, ModularGroup, ModularMonoid>
{
public ModularGroup AdditiveStructure { get; set; }
public ModularMonoid MultiplicativeStructure { get; set; }
}
Alternatively, you should consider making the properties read-only. That way, if you're happy with the ModularRing users only using the IGroup<int> and IMonoid<int> definitions (rather than depending on anything extra exposed on ModularGroup and ModularMonoid) then you could stick with just the single type parameter, which would simplify things quite a lot. For example:
public interface IMonoid<T> : ISemiGroup<T>
{
T Identity { get; }
}
public interface IGroup<T> : IMonoid<T>
{
T Inverse(T a);
}
public interface IRing<T>
{
IGroup<T> AdditiveStructure { get; }
IMonoid<T> MultiplicativeStructure { get; }
}
Implementation:
public class ModularRing : Scaffolding.IRing<int>
{
public IGroup<int> AdditiveStructure { get; } = new ModularGroup();
public IMonoid<int> MultiplicativeStructure { get; } = new ModularMonoid();
}
(Or accept them in the constructor; I don't know enough about what you're trying to do with them.)
I have a few classes that inherit from a base class for which I wish to change the implementation of a property and method. I also require the base class and all sub classes to be be polymorphic, so I can later create a collection of any type that implements a particular interface.
When i create instances of my classes that implement an interface, I want to use properties and methods on that class (implemented by the interface), not the base class.
This is my simplified implementation of the issue that provides the desired output but does have a code smell...
class Program
{
static void Main(string[] args)
{
IGrid one = new TextField();
IGrid two = new SelectList();
one.Click();
two.Click();
Console.WriteLine(one.Text);
Console.WriteLine(two.Text);
Console.ReadLine();
}
}
public interface IGrid {
string Text { get; set; }
void Click();
}
public class Control : IGrid {
public string Text {
get { return "Hello Control!"; }
set { }
}
public virtual void Click() {
Console.WriteLine("In the Control!");
}
}
public class SelectList : Control, IGrid {
public int Number { get; set; }
public new string Text {
get {
return "Hello Select!";
}
set { Number = int.Parse(value); }
}
public override void Click() {
Console.WriteLine("In the Select!");
}
}
public class TextField : Control, IGrid {
public int Number { get; set; }
public new string Text {
get {
return "Hello TextField!";
}
set { Number = int.Parse(value); }
}
public override void Click()
{
Console.WriteLine("In the TextField!");
}
}
This works but feels a little messy having an empty set in the Control class.
Is there a cleaner approach to this type of problem without compromising on specific property implementations on sub classes?
Many thanks,
Okay, so first thing is first, you should not be changing another property when you set a property (like you are doing to Number from Text). This is a huge code smell because it is a side effect. You should always deal directly with the properties that you intend to.
public class SelectList : Control, IGrid {
public int Number { get; set; }
public new string Text {
get {
return "Hello Select!";
}
// This is bad, someone after you may not know that this has a side effect
set { Number = int.Parse(value); }
}
}
Second, a property can be virtual just like a method, so marking your Text property as virtual and overridding in a derived class will make polymorphism work the way it is intended. "Hiding" via the new keyword would require you to cast your interface its specific class in order to get that classes implementation.
public class Control : IGrid
{
public virtual string Text
{
get { return "Hello Control!"; }
}
public virtual void Click()
{
Console.WriteLine("In the Control!");
}
}
public class SelectList : Control, IGrid
{
public int Number { get; set; }
public override string Text
{
get
{
return "Hello Select!";
}
}
public override void Click()
{
Console.WriteLine("In the Select!");
}
}
Third, you do not have to have a setter on the interface. You could just have a getter and only need to implement that.
public interface IGrid
{
string Text { get; }
void Click();
}
Finally, if you are ALWAYS going to override a method or property and NEVER going to create the base class directly (with a new) then you should consider using an abstract class if you have shared implementation (EG at least one method or property you do not change) or don't bother with the base class because you are not using any of the code anyways.
// Abstract class
public abstract class Control : IGrid
{
// Property that is not overridden but is shared
public int Number { get; set; }
public abstract string Text
{
get;
}
public abstract void Click();
}
public class SelectList : Control
{
// Don't need the Number property here, base class has it
public override string Text
{
get
{
return "Hello Select!";
}
}
public override void Click()
{
Console.WriteLine("In the Select!");
}
}
// Need everything in this class, but if it is all different anyways
// then base class is kind of a waste
public class TextField : IGrid
{
public int Number { get; set; }
public string Text
{
get
{
return "Hello TextField!";
}
}
public void Click()
{
Console.WriteLine("In the TextField!");
}
}
Well from the beginning, I've got a simple generic interface:
public interface IItemContainer<T> where T : Item
{
T ChosenItem { get; set; }
}
And an class that implements it multiple times:
public class ChosenItemsContainer : IItemContainer<FabulousItem>, IItemContainer<NiceItem>, IItemContainer<GreedyItem>
{
public FabulousItem ChosenItem { get; set; }
NiceItem IItemContainer<NiceItem>.ChosenItem { get; set; }
GreedyItem IItemContainer<GreedyItem>.ChosenItem { get; set; }
}
I can't make the ChosenItems of types NiceItem and GreedyItem public, and also I can't access it like this:
ChosenItem<GreedyItem> = new GreedyItem();
cuz' I've got an error:
'GreedyItem' is a type, which is not valid in the current context
Is there anyway to use those props in this manner or I've got it all wrong and should do It with Dictionary or other way?
When you like to keep your generic IItemContainer you can implement a GetChosenItem and SetChosenItem method like this.
public class ChosenItemsContainer : IItemContainer<FabulousItem>, IItemContainer<NiceItem>, IItemContainer<GreedyItem>
{
FabulousItem IItemContainer<FabulousItem>.ChosenItem { get; set; }
NiceItem IItemContainer<NiceItem>.ChosenItem { get; set; }
GreedyItem IItemContainer<GreedyItem>.ChosenItem { get; set; }
public T GetChosenItem<T>()
where T : Item
{
return ((IItemContainer<T>)this).ChosenItem;
}
public void SetChosenItem<T>(T value)
where T : Item
{
((IItemContainer<T>)this).ChosenItem = value;
}
}
Which comes very close to what you were trying to do.
container.SetChosenItem<NiceItem>(new NiceItem());
Yours is a case explicit interface implementations were made for. You give your conflicting items a unique name and forward the items to the interface. That also avoids any naming confusions:
public class ChosenItemsContainer : IItemContainer<FabulousItem>, IItemContainer<NiceItem>, IItemContainer<GreedyItem> {
public FabulousItem ChosenFabulousItem { get; set; }
public NiceItem ChosenNiceItem { get; set; }
public GreedyItem ChosenGreedyItem { get; set; }
FabulousItem IItemContainer<FabulousItem>.ChosenItem {
get {
return ChosenFabulousItem;
}
set {
ChosenFabulousItem = value;
}
}
NiceItem IItemContainer<NiceItem>.ChosenItem {
get {
return ChosenNiceItem;
}
set {
ChosenNiceItem = value;
}
}
GreedyItem IItemContainer<GreedyItem>.ChosenItem {
get {
return ChosenGreedyItem;
}
set {
ChosenGreedyItem = value;
}
}
}
Assignment is simple:
container.ChosenFabulousItem = new FabulousItem();
container.ChosenNiceItem = new NiceItem();
container.ChosenGreedyItem = new GreedyItem();
If you have more complex conversion logic in the background (e.g. you assign a FaboulousItem and need to convert it into a NiceItem), you can do so by providing getters and/or setters for your public properties.
It's completely wrong. As you should know you cannot make same names for member items (properties, fields etc. ). It will confuse compiler.
I would suggest to modify your interface a bit like :
public interface IItemContainer
{
List<Item> ChosenItems { get; set; }
T ChosenItem<T>() where T : Item;
}
Now in your implementation :
public class ItemContainer : IItemContainer
{
IItemContainer.ChosenItems
{
get { // your implementation
}
set { // your implementation
}
}
T IItemContainer.ChosenItem<T>()
{
return ((IItemContainer)this).ChosenItems.OfType<T>().FirstOrDefault();
}
}
This method will let you store different objects that derive from Item and return desired one using ChosenItem<T>() method.
EDIT:
I've got another interface which operates on List of Items, cuz' some submodules works only on one Item, and some only on set. I need also to store an instance of each implemented type independently.
You can always use something like a factory collection ( dont know if the name is correct ).
public class ChosenItemCollection
{
Dictionary<Type, Item> _fac = new Dictionary<Type, Item>();
public T Add<T>(T item) where T : Item
{
if(!_fac.ContainsKey(typeof(T))
{
_fac.Add(typeof(T), item);
}
else
{
_fac[typeof(T)] = item;
}
}
public T GetChosenItem<T>() where T : Item
{
if(_fac.ContainsKey(typeof(T))
return _fac[typeof(T)];
return null;
}
}
Then in your interface instead of List<Item> ChosenItems you can do ChosenItemCollection ChosenItems.
Using this in your example :
GreedyItem item = // ...
ItemContainer.ChosenItems.Add(item);
ItemContainer.ChosenItem.ChosenItem<GreedyItem>();
I think Pidon has a nice solution. But could result in a runtime error when using not implemented Item derives.
Another solution could be adding properties which will do the casts to the implemented types:
public class ChosenItemsContainer : IItemContainer<FabulousItem>, IItemContainer<NiceItem>, IItemContainer<GreedyItem>
{
// these properties are only visible when casting to the correct
// interface. Which the public properties below will do.
FabulousItem IItemContainer<FabulousItem>.ChosenItem { get; set; }
GreedyItem IItemContainer<GreedyItem>.ChosenItem { get; set; }
NiceItem IItemContainer<NiceItem>.ChosenItem { get; set; }
// return this as IItemContainer<FabulousItem>
public IItemContainer<FabulousItem> AsFabulous
{
get
{
return (IItemContainer<FabulousItem>)this;
}
}
// return this as IItemContainer<NiceItem>
public IItemContainer<NiceItem> AsNice
{
get
{
return (IItemContainer<NiceItem>)this;
}
}
// return this as IItemContainer<GreedyItem>
public IItemContainer<GreedyItem> AsGreedy
{
get
{
return (IItemContainer<GreedyItem>)this;
}
}
}
ChosenItemsContainer container = new ChosenItemsContainer();
container.AsFabulous.ChosenItem = new FabulousItem();
container.AsNice.ChosenItem = new NiceItem();
container.AsGreedy.ChosenItem = new GreedyItem();
This way each implemented type has it's own ChosenItem instance. I think this is a clean solution without cluttering of generic <T> in code.
I am trying to make my method generic and I am stuck at a point and need your assistance. The code scenario is I have an abstract class say MyBaseAbs which contains common properties:
public abstract class MyBaseAbs
{
public string CommonProp1 { get; set; }
public string CommonProp2 { get; set; }
public string CommonProp3 { get; set; }
}
Now I have child classes:
public class Mychild1: MyBaseAbs
{
public string Mychild1Prop1 { get; set; }
public string Mychild1Prop2 { get; set; }
public string Mychild1Prop3 { get; set; }
}
and another child class:
public class Mychild2: MyBaseAbs
{
public string Mychild1Prop1 { get; set; }
public string Mychild2Prop2 { get; set; }
}
Now I have to create a common method which needs to perform some operations on the basis of Mychild1 and Mychild2, so what I did is:
public MyCustomClass SaveOperation<T>(T myObj)
where T : MyBaseAbs
{
SaveObject obj = new SaveObject();
}
so inside this method I need to write common code which does the mapping for SaveObject object according to the child object passed. How can I determine which object is passed and use properties accordingly.
One option would be to create a base Save function in your base class and make it virtual.
Then override the method in your child classes. This way when you call the Save method in your SaveOperation it should call the appropriate method from the correct child class.
public abstract class MyBaseAbs
{
public string CommonProp1 { get; set; }
public string CommonProp2 { get; set; }
public string CommonProp3 { get; set; }
public virtual void Save() { }
}
public class Mychild1: MyBaseAbs
{
public string Mychild1Prop1 { get; set; }
public string Mychild1Prop2 { get; set; }
public string Mychild1Prop3 { get; set; }
public override void Save() {
//Implementation for Mychild1
}
}
public class Mychild2: MyBaseAbs
{
public string Mychild1Prop1 { get; set; }
public string Mychild2Prop2 { get; set; }
public override void Save() {
//Implementation for Mychild2
}
}
If you can't modify your business objects, you can check the type of the concrete class in the SaveOperation method:
public MyCustomClass SaveOperation<T>(T myObj)
where T : MyBaseAbs
{
SaveObject obj = new SaveObject();
if (myObj is Mychild1) {
Mychild1 mychild1 = (Mychild1) myObj;
// Business logic for object of type Mychild1
} else if (myObje is Mychild2) {
Mychild2 mychild2 = (Mychild2) myObj;
// Business logic for object of type Mychild2
}
}
Notice that this is not a very solid solution as, if you are creating new objects that implement your abstract class, you will have to remeber to add another branch in the if statement.
As #BojanB mentioned, the obvious solution would be to create a virtual method in your base class and override it in the derived, but if you cannot modify the code there then you can create a method for each derived class and create a dictionary that maps each type to its method:
private Dictionary<Type, Action<MyBaseAbs, MyCustomClass>> _saveOperations =
new Dictionary<Type, Action<MyBaseAbs, MyCustomClass>>();
//You can then set an entry for each of your derived classes
_saveOperations[typeof(Mychild1)] = (myObj, myCustomObj) =>
{
//Mychild1-specific logic
};
public MyCustomClass SaveOperation(MyBaseAbs obj)
{
//do the common saving operations here
var result = new MyCustomClass();
//....
var actualType = obj.GetType();
if(_saveOperations.ContainsKey(actualType))
{
_saveOperations[actualType](obj, result);
}
return result;
}
You can then add an item to the dictionary for each derived class. It is the same concept as using the is operator but allows you to add methods for more derived types without modifying the original SaveOperation method
You can use C#'s As-Operator as follows:
Mychild1 child1 = myObj as Mychild1;
if(child1 != null) {
//Here you can use child1.Mychild1Prop1 forexample
}
Link to msdn: https://msdn.microsoft.com/en-us/library/cscsdfbt.aspx
I want to create a class that can take different types of value in a property. I am trying to do this using polymorphism, but I am not still learning how to do this properly, hence my request for advice.
I have a base class and two classes that inherit from it:
public abstract class BaseClass
{
public string Name { get; set; }
public Unit Unit { get; set; }
}
public class DerivedClassFloat : BaseClass
{
public float Value { get; set; }
public override string ToString()
{
return Value.ToString();
}
}
public class DerivedClassString : BaseClass
{
public string Value { get; set; }
public override string ToString()
{
return Value;
}
}
All is good, I can create a List and add different specialized subclasses. My problem comes when I need change the values of the items in my list:
foreach (var item in ListOfBaseClasses)
{
if(item is DerivedClassFloat)
((DerivedClassFloat) item).Value = float.NaN;
if (item is DerivedClassString)
((DerivedClassString) item).Value = string.Empty;
}
According to what I have read, that looks like a code smell. Is there a better way to access the value property of my derived classes based on the type I am trying to assign?
What about when you want to create the right subclass based on the value?
BaseClass newClass = null;
if (phenotype is DerivedClassFloat)
newClass = new DerivedClassFloat(){Value = 12.2};
if (phenotype is DerivedClassString)
newClass = new DerivedClassString(){Value = "Hello"};
I read about overriding virtual methods, but that works if I want to process the value, not to add or change it … maybe I am missing something?
I should make this more concrete, my apologies, I am not used to post question in this great site.
I need a property that is made of a list of attributes. Each attribute has a name and a value, but the value can be of different types. For example:
public class Organism
{
public string Name { get; set; }
public List<Attribute> Attributes { get; set; }
}
public class Attribute
{
public string AttributeName { get; set; }
public object AttributeValue { get; set; }
}
For a given organism I can have several attributes holding different value types. I wanted to avoid using the object type so that I don’t have to cast to the right type. I though property polymorphism was the solution to handle this case elegantly, but then I found myself using If ..Then which didn’t seem too different from casting in the first place.
If in your particular case you want to reset Value, you can define an abstract ResetValue method in the base class, which will be implemented by the derives classes.
As for your second case, you should check out Creational Design Patterns, and specifically the Factory and Prototype design patterns.
You can use generics to define the type and the implementing subclass will set the Value type to the type constraint:
public abstract class BaseClass<T>
{
public string Name { get; set; }
public Unit Unit { get; set; }
public T Value { get; set; }
public override string ToString()
{
return Value.ToString();
}
}
public class DerivedFloat : BaseClass<float> {}
public class DerivedString : BaseClass<string> {}
You can use Generics for this particular case:
public abstract class BaseClass<T>
{
public string Name { get; set; }
public Unit Unit { get; set; }
public T Value { get; set; }
}
public class DerivedClassFloat : BaseClass<float>
{
public override string ToString()
{
return Value.ToString();
}
}
public class DerivedClassString : BaseClass<string>
{
public override string ToString()
{
return Value;
}
}
Polymorphic behaviour works on abstraction. Based on what your trying to do, you can reduce code smell to moving as much of your variability in code to base classess.
i would suggest is instead of property write method like as follows. You can something like as follows.
public void setValue(string val, Type type);//move this to your base class
Class MyValue{
private string strVal;
private int intVal;
//constructor
MyValue(string val, Type type){
//check the type enum here and set the values accordingly
}
}
then when set values
foreach (var item in ListOfBaseClasses)
{
item.setValue = MyValue("",Type.INT);
}
I'm not quite sure what you are trying to achieve with this approach - the Value properties are not of the same type, there is also no Value property on the base class which suggests that other types derived from the base class might not have it at all.
If all of your classes require a Value property, then maybe it should be of the most general type object - you could put it onto the base class, but that would require casting the values in the derived classes.
But then you could have a NullObject to represent an absence of value that you could assign to the Value property for every derived class.
You can use the abstract factory pattern. Consider this example:
// Base class
class Button
{
protected Button()
{
}
public string Name { get; set; }
}
// Factory interface
public interface ButtonFactory
{
Button CreateButton();
}
// And the concrete classes
class WindowsButton : Button
{
// ...
}
class WindowsButtonFactory : ButtonFactory
{
public Button CreateButton()
{
return new WindowsButton();
}
}
class MacButton : Button
{
// ...
}
class MacButtonFactory : ButtonFactory
{
public Button CreateButton()
{
return new MacButton();
}
}
Furthermore, you can combine the abstract factory pattern with the strategy pattern to encapsulate the custom behaviors that change with type.