Correct way to implement inheritance in C# [closed] - c#

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
The following example works fine, but it has a flaw: the Square object has the Width and Height properties of the Rectangle. A good implementation of the Square object won't provide these properties to the user:
public class Rectangle
{
public double Width { get; set; }
public double Height { get; set; }
public double Area { get { return Width * Height; } }
}
public class Square : Rectangle
{
public double Side
{
get { return Width; }
set { Width = Height = value; }
}
}
I thought of a few ways to fix that (including new properties and the Obsolete tag). The best solution was to cancel the inheritance, and instead keep a Rectangle as a private variable of the Square object. This would work, but will require re-writing the Rectangle methods for Square, which is against the whole purpose of OOP. Please help me understand what is the right way to implement this.
Thanks

I don't agree that Square shouldn't provide Width and Height properties since squares absolutely do have a width and height just like any rectangle. The only difference is that they are necessarily the same.
The way I'd fix it, is to either make a Rectangle immutable, or allow Square to override the properties:
public class Rectangle
{
public virtual int Width { get; set; }
public virtual int Height { get; set; }
public Rectangle(int width, int height)
{
Width = width;
Height = height;
}
}
public class Square : Rectangle
{
public override int Width
{
get { return Side; }
set { Side = value; }
}
public override int Height
{
get { return Side; }
set { Side = value; }
}
public int Side { get; set; }
public Square(int side)
: base(side, side)
{
Side = side;
}
}

That's a common problem that some people answer with "OOP is not the silver bullet". But if you really want to use OOP mechanisms here, you could override the Width to always be the Height for a square. So if you set one, the other changes as well. Not perfect, but it works.
public class Rectangle
{
public virtual double Width { get; set; }
public virtual double Height { get; set; }
public double Area { get { return Width * Height; } }
}
public class Square : Rectangle
{
public override double Width { get { return Height; } set { Height = value; } }
}

Don't inherit Square from Rectangle. You are trying to have the relation between your abstractions same as the relation between objects which they represent. But think about following
When the spouses are getting divorced each one of them has the lawyer which represents them. It's very unlikely that those two lawyers themselves are getting divorced. Because the representatives of things do not share the relationships of things they represent © Uncle Bob
Your Square class represents square geometric shape. But it's not a geometric shape. It's a code. Same with Rectangle class. And relationship between geometric shapes are not shared by these representatives. Let's talk about problems which you will have if you will try to share relationship between geometric square and rectangle with Square and Rectangle classes in your code.
If you inherit Square from Rectangle then you can treat any square as base class:
var rectangle = new Square { Side = 10 };
rectangle.Width = 20;
Now you have 'square' object with width 20 and height 10. Did you expect to have such square? OK, you can synchronize those properties. I.e. when you change width, height will change as well and vice versa:
rectangle.Width = 5;
rectangle.Height = 10;
Assert.That(rectangle.Area, Is.EqualTo(50)); // wtf it fails?
Did you expect that height also will be 5 if you are using variable of base type (rectangle)? It's not valid behavior of rectangle. And it violates Liskov Substitution Principle.
If you will not inherit Square from Rectangle - none of those problems will appear. Square will have single property Side and it will behave as you expect. The only case when you might inherit Square from Rectangle without having unexpected values of width or height - if make those object immutable. But another problem will stay - your square still will have properties Width and Height which are confusing. It should have only one property Side.

Setting the Rectangle properties to virtual will allow you to override their behaviors and have square inherit Rectangle.
Please see the example below for more information:
public class Rectangle
{
public virtual double Width { get; set; }
public virtual double Height { get; set; }
public double Area { get { return Width * Height; } }
}
public class Square : Rectangle
{
public double Side { get; set; }
public override double Height
{
get { return Side; }
set { Side = value; }
}
public override double Width
{
get { return Side; }
set { Side = value; }
}
}

Related

Concept regarding Upcasting, Inheritance and setting property using object initializer

The title of the question may seem confusing but bear with me, I'll try to explain the problem as clearly as possible.
So I was just studying about the Liskov substitution principle from a course and the lecturer has given an example showing logical errors we can solve using this principle. Hence, the example shown below is the problem with the logical error.
(Note: Please read the whole question even if you don't know/find out this example has nothing to do with Liskov principle as I've mentioned that above. I've just kept this in question for reference, just in case someone bothers to answer that you're doing it the wrong way)
Rectangle is the parent class
class Rectangle
{
public int Width { get; set; }
public int Height { get; set; }
public Rectangle()
{
}
public Rectangle(int width, int height)
{
Width = width;
Height = height;
}
public override string ToString()
{
return $"{nameof(Width)}: {Width}, {nameof(Height)}: {Height}";
}
}
Square class
class Square : Rectangle
{
public new int Width
{
set { base.Width = base.Height = value; }
}
public new int Height
{
set { base.Width = base.Height = value; }
}
}
Just a simple Caller
private void Caller()
{
Rectangle rc = new Square(); //Upcasting here
rc.Width = 4;
Console.WriteLine($"{rc}"); //Now here the o/p is **Width: 4, Height: 0** which is correct
//But when we use object initializer as shown below
Rectangle rcTwo = new Square { Width = 4 };
Console.WriteLine($"{rcTwo}"); //the o/p is **Width: 4, Height: 4**
}
Now aren't we just initializing the object in a different way? Why is the O/P supposed to differ in that case. I thought that object initializer is just an syntactical sugar when when we to create an object and initialize it's properties in comparison with the traditional approach.
You are right that it's syntactical sugar. But you have to think of the order of operations: assignment is done last, after all the operations on the right of the equals sign. So your second version with initialiser is the same as:
Square square = new Square();
square.Width = 4;
Rectangle rcTwo = square;

Using System.Windows.Size as universal "size" instead of UI controls size

It is appropriate to use System.Windows.Size for describing, for example, sizes of buildings in my app, or should I create my own structure for it? This domain has nothing to do with System.Windows or displays.
public struct Size
{
public Size(double length, double width) : this()
{
Length = length;
Width = width;
}
public double Length { get; set; }
public double Width { get; set; }
}
Thanks.
Create your own struct since Size is platform specific. For example, Xamarin.Forms have different Size structure.
And make your size immutable. It's a bad practice to create mutable structures.

Inheritance error S57036 There is no argument given [duplicate]

This question already has answers here:
C# inheritance and default constructors
(4 answers)
Inheritance with base class constructor with parameters [duplicate]
(2 answers)
Using an abstract class create different classes with user input
(2 answers)
Closed 5 years ago.
I am new to C# and struggling through a tutorial printout. My intention is to inherit properties from the class Rectangle. However I am getting an error I cant resolve. any tips appreciated thank you
Error C57036 There is no argument given that corresponds to the required formal parameter 'a' of 'Rectangle.Rectangle(double, double)'
{
{
//private static void Main(string[] args)
{
Rectangle myRectangle = new Rectangle(23.5, 8.6);
Console.WriteLine(myRectangle.getArea().ToString());
Console.WriteLine(myRectangle.getParimeter().ToString());
Square mySquare = new Square(15);
Console.WriteLine(mySquare.getArea().ToString());
Console.WriteLine(mySquare.getParimeter().ToString());
Console.ReadLine();
}
}
class Rectangle
{
private double length;
private double width;
public Rectangle(double a, double b)
{
length = a;
width = b;
}
public double getArea()
{
return this.length * this.width;
}
public double getParimeter()
{
return 2 * (this.length + this.width);
}
}
class Square : Rectangle
{
public Square(double a)
{
length = a;
}
}
}
Rectangle has no public constructor without arguments, so you need to declare your constructor and call suitable base constructor with arguments:
class Square : Rectangle
{
public Square(double a) : base(a, a)
{
}
}
This also solves the problem of accessing private property in your code.
This should solve compilation error.
However, in your case it looks like you can go right into the most popular Liskov Substitution Principle violation case if you make your class mutable.
In short, in case of mutability you cannot inherit Square from Rectangle even if it sounds logical in real world. It is not possible to implement changing width or height of rectangle so that it behaves correctly in all cases.
Read more about it here:
Is deriving square from rectangle a violation of Liskov's Substitution Principle?
P.S. Please, follow C# naming guidelines. Methods should have an UpperCamelCase name like GetArea or GetPeremiter. When you see a method with name starting with Get, then you probably want it to become a property:
class Rectangle
{
private double _length;
private double _width;
public Rectangle(double a, double b)
{
_length = a;
_width = b;
}
public double Area => this.length * this.width;
public double Perimeter => 2 * (this.length + this.width);
}

C# Objects and Constructors best practices

namespace Area
{
public class Rectangle
{
private double length;
private double width;
public Rectangle() { }
public Rectangle(double length, double width)
{
this.Length = length;
this.Width = width;
}
public double Length
{
get
{
return length;
}
set
{
length = value;
}
}
public double Width
{
get
{
return width;
}
set
{
width = value;
}
}
public double getArea()
{
return width * length;
}
public double getPerimeter()
{
return 2 * width + 2 * length;
}
public double getDiagonal()
{
return Math.Sqrt(Math.Pow(width, 2) + Math.Pow(length, 2));
}
I want to make sure I am using best practices with C# Objects. Please use the above example for reference.
1. Is it necessary that I type the first empty Constructor? In class the Instructor always did on each program but never really gave an answer as to why.
public Rectangle() { }
2. Inside my Custom Constructor Visual Studio generates it like this:
this.Length = length;
I know that the "this" keyword is not necessary the way it is typed, but in class the instructor sometimes changed it to lowercase like this:
this.length = length;
But sometimes he didn't change it. Which way is best practices?
And is the left side the actual Property? And then the right side is the field?
So it is, Property equals field?
3. And finally, in this case cant I just type my properties as:
public string Length { get; set; }
instead of the way Visual Studio generates with the return and value.
Sorry for the long post, I am tired of getting different answers at school and want one final answer on this, thanks.
I would suggest that your class look like this:
public class Rectangle
{
public Rectangle(double length, double width)
{
this.Length = length;
this.Width = width;
}
public double Length { get; set; }
public double Width { get; set; }
public double Area { get { return this.Width * this.Length; } }
public double Perimeter { get { return 2.0 * (this.Width + this.Length); } }
public double Diagonal { get { return Math.Sqrt(Math.Pow(this.Width, 2.0) + Math.Pow(this.Length, 2.0)); } }
}
See here for why you might want a blank constructor. To summarize, adding a non blank constructor will stop the compiler from generating a blank one for you (the compiler assumes that if you wanted it, you would have defined it with the other constructors you wrote). Some things, like serialization, will not work without a blank constructor, so that's a reason you might want to add one.
In my career, I've mostly seen people avoid using this in constructors. Maybe avoid isn't the right word, but unless it's unclear, they just didn't bother to put it there. This is probably too minor an issue to lose any sleep over.
UPDATE based on some of your comments
When you write
public Rectangle(double length, double width)
{
Length = length; //parameter length assigned to field length by virtue of property Length
}
you are assigning the parameter length to the property Length, which itself assigns the passed in value to the length private field. Since C# is case sensitive, Length and length aren't confused in any scenario, and you don't need to specify the this keyword.
Inside a method with a parameter called length, the language is assuming that you are referring to the parameter of the method when you type length. So if you try to do something like this:
public Rectangle(double length, double width)
{
length = length; //warning: Assignment made to same variable; did you mean to assign to something else
}
The compiler doesn't try and assume that you are assigning the property to the field, and this is just assigning the length parameter to itself. In this case, you would use the this keyword to tell the compiler that you want to assign the parameter length to the private field length, like this:
public Rectangle(double length, double width)
{
this.length = length; //no warning
}
END UPDATE
Yes, you could declare the property as just Property {get;set;}. This feature is only from C# 3.0 and is called auto-implemented properties (see this link). Before that you had to provide the implementation yourself.
I changed my class to this:
public class Rectangle
{
public Rectangle(double length, double width)
{
Length = length;
Width = width;
}
public double Length { get; set; }
public double Width { get; set; }
public double getArea()
{
return Width * Length;
}
public double getPerimeter()
{
return 2 * Width + 2 * Length;
}
public double getDiagonal()
{
return Math.Sqrt(Math.Pow(Width, 2) + Math.Pow(Length, 2));
}
}
If anyone has any other feedback on anything above that you recommend to change please give it, I catch on very fast and want to learn the correct way.

Reducing number of very long constructor overloads with just a few different parameters

I made custom interface system which uses basic UI controls like button, label, etc. Some controls have many options, so they use long constructors, and they only differ in one or two parameters. And this is work in progress, so I change optional parameters a lot, and it takes quite some time to apply changes to all constructors.
public Button(string Text, Rectangle Rect, Texture2D Texture, bool moreStuff)
public Button(string Text, Point Position, Texture2D Texture, bool moreStuff)
public Button(string Text, Vector2 Position, Texture2D Texture, bool moreStuff)
I tried using dynamic keyword instead of Rectangle, Point and Vector2 to decrease the number of constructors, and it compiles, works, and seems ok for the moment. But maybe I'm missing something that might break this approach later?
To find out what was passed as dynamic Position I check for .GetType().Name, use a switch and throw an exception at default: if it wasn't a recognized type.
Is it fine to do it like this, or is there a better (more safe or appropriate) way?
Currently it's possible to create a fully customized instance of Button inline, and I wouldn't like to lose that ability.
You don't need to define constructor arguments if you're finding it tedious. You could use an object initializer quite nicely:
SomeButton button = new SomeButton()
{
Text = "",
MoreStuff = false
};
This calls for a parameter object. That's a class with a property per parameter. Your Button constructor would now only take one parameter: That parameter object.
Using dynamic to reduce the number of overloads is definitely not the correct approach.
Using dynamic is not appropritate in your scenario. Having differenct constructor overloads is not a bad thing (not worth than abusing the dynamic keyword). Many classes in .NET Framework BCL has several constructor overloads (for example, FileStream class has 15 contstructors) and some methods has several overload for differenct uses (MessageBox.Show for example).
Another approach is to type this yourself:
class YourPositioningType {
public int X { get; set; }
public int Y { get; set; }
public static YourPositioningType FromVector(Vector2 vector) {
return new YourPositioningType() { X = vector.X, Y = vector.Y };
}
public static YourPositioningType FromRectangle(Rectangle rect) {
// etc..
}
}
Static methods to convert from each of the above types. Then you would call it as:
Button b = new Button("Blah", YourPositioningType.FromVector(new Vector2() { /* etc */));
Then you just use the above class in a single constructor.
If you use object initialisers, then you can set each individual property you require independently. You just have to be careful that the various properties can be initialised independently.
For example:
public class Button
{
public int Width
{
get
{
return Rectangle.Width;
}
set
{
Rectangle.Width = value;
}
}
public int Height
{
get
{
return Rectangle.Height;
}
set
{
Rectangle.Height = value;
}
}
public int X
{
get
{
return Rectangle.Left;
}
set
{
Rectangle.Left = value;
}
}
public int Y
{
get
{
return Rectangle.Top;
}
set
{
Rectangle.Top = value;
}
}
public Rectangle Rectangle
{
get;
set;
}
}
If you had a class like the above, you can do either:
var button = new Button
{
Rectangle = new Rectangle(...)
}
or:
var button = new Button
{
Left = 0,
Top = 0,
Width = 100,
Height = 20
}
Object initializer notation is ideal for initializing object via their properties where you can have multiple combinations of properties needing to be set.

Categories

Resources