C# Inheritance and Methods - c#

I'm learning inheritance and I understand the code below.
namespace InheritanceApplication {
class Shape {
public void setWidth(int w) {
width = w;
}
public void setHeight(int h) {
height = h;
}
protected int width;
protected int height;
}
// Base class PaintCost
public interface PaintCost {
int getCost(int area);
}
// Derived class
class Rectangle : Shape, PaintCost {
public int getArea() {
return (width * height);
}
public int getCost(int area) {
return area * 70;
}
}
class RectangleTester {
static void Main(string[] args) {
Rectangle Rect = new Rectangle();
int area;
Rect.setWidth(5);
Rect.setHeight(7);
area = Rect.getArea();
// Print the area of the object.
Console.WriteLine("Total area: {0}", Rect.getArea());
Console.WriteLine("Total paint cost: ${0}" , Rect.getCost(area));
Console.ReadKey();
}
}
}
However, why have they created the set height and set width functions. Would it not be better practice to simply just do this:
public int width {get;set;}
public int height {get;set;}
and then in the main class just do something like below:
rect.width = 5;
rect.height = 7;
Many thanks,
Amir

I'm sure others will provide different points, but here are my main 2 reasons for using gets/sets. If these don't apply for a given property, chances are I won't use getters/setters.
1 - Debugging
It makes it significantly easier to debug data propagation (how data gets passed around) if you can debug a setter that you're concerned about. You can easily throw in a Debug.Print call and debug the value being set if you're concerned it's being passed the wrong value. Or you could place break points and actually debug through the stack trace. For example:
class Shape {
public void setWidth(int w) {
if(w < 0)
Debug.Print("width is less than 0!");
width = w;
}
public void setHeight(int h) {
height = h;
}
protected int width;
protected int height;
}
2 - Value Change Actions
There may be better ways to achieve this, but I like being able to add simple logic to setters to ensure that any logic that needs to run when a value changes does so. For instance I may use the following:
public void SetWindowHeight(int newHeight)
{
if(WindowHeight == newHeight)
return;
WindowHeight = newHeight;
UpdateWindowDisplay();
}
public int GetWindowHeight()
{
return WindowHeight;
}
private int WindowHeight;
public void UpdateWindowDisplay()
{
Window.UpdateHeight(WindowHeight);
// Other window display logic
}
Although personally I prefer to use property gets/sets, but that's just my preference.
public int WindowHeight
{
get
{
return windowHeight;
}
set
{
if(windowHeight == value)
return;
windowHeight = value;
UpdateWindowDisplay();
}
}
private int windowHeight;
public void UpdateWindowDisplay()
{
Window.UpdateHeight(WindowHeight);
// Other window display logic
}

Related

Weird GUI issue in cosmos

When i do display.init() I get these white lines and a few other different pixels. The next thing that happens is they disappear one line at a time and it's preventing my VGA from booting.
I'll post my kernel code and display driver.
DISPLAY DRIVER C#
using Cosmos.HAL;
using Sys = Cosmos.System;
namespace Display
{
public class DisplayDriver
{
protected VGAScreen screen;
private int width, height;
public DisplayDriver()
{
screen = new VGAScreen();
}
public void init()
{
screen.SetGraphicsMode(VGAScreen.ScreenSize.Size320x200, VGAScreen.ColorDepth.BitDepth8);
screen.Clear(0);
width = screen.PixelWidth;
height = screen.PixelHeight;
}
public virtual void setPixel(int x, int y, int c)
{
if (screen.GetPixel320x200x8((uint)x, (uint)y) != (uint)c)
setPixelRaw(x, y, c);
}
public virtual byte getPixel(int x, int y)
{
return (byte)screen.GetPixel320x200x8((uint)x, (uint)y);
}
public virtual void clear()
{
clear(0);
}
public virtual void clear(int c)
{
screen.Clear(c);
}
public virtual void step() { }
public int getWidth()
{
return width;
}
public int getHeight()
{
return height;
}
public void setPixelRaw(int x, int y, int c)
{
screen.SetPixel320x200x8((uint)x, (uint)y, (uint)c);
}
}
}
KERNEL:
using System;
using Sys = Cosmos.System;
using Display;
using Cosmos.Core;
using Cosmos.HAL;
using Cosmos.Common;
using Cosmos.Debug;
using Cosmos.IL2CPU;
namespace CosmosKernel3
{
public class Kernel : Sys.Kernel
{
protected override void BeforeRun()
{
Console.WriteLine("Booting VGADriver.");
try
{
var display = new DisplayDriver();
Console.WriteLine("ATTEMPTING");
display.init(); //init display
display.clear();
display.setPixel((int)40, 50, 60);
}
catch (Exception)
{
Console.WriteLine("Booting VGA failed. Booting into DOS mode.");
dosemergency();
}
}
protected override void Run()
{
boot();
while (true) ;
}
public static void boot()
{
}
public static void dosemergency()
{
Console.WriteLine("XENA DOS EMERGENCY MODE.");
Console.WriteLine("COMMANDS:");
Console.WriteLine("graphics -r (Graphics retry)");
String meow = Console.ReadLine();
if (meow == "graphics -r") ;
Console.WriteLine("Booting VGADriver.");
try
{
var display = new DisplayDriver();
display.init(); //init display
boot(); //boot
}
catch (Exception)
{
Console.WriteLine("Booting VGA failed. Booting into DOS mode.");
dosemergency();
}
}
}
}
SCREENSHOT:
Anyway, this has been happening for a while now and I cant seem to figure out why its doing this. Help!
I don't know if it's not too late, however this issue is popular in Cosmos, so future readers might find this answer.
Your code is correct. After talking with one of the devs he told me that they are aware of the issue and it happens because
current code [of Cosmos] uses delegates for pixelputting
If you wait 1-2 minutes, the screen will finally load.
edit:
I found a way to speed up this process a lot:
never call
Screen.clear()
function
Instead create the following function:
public void DrawFilledRectangle(uint x0, uint y0, int Width, int Height, int color)
{
for (uint i = 0; i < Width; i++)
{
for (uint h = 0; h < Height; h++)
{
setPixel((int)(x0 + i), (int)(y0 + h), color);
}
}
}
and replace
public virtual void clear(int c)
{
screen.Clear(c);
}
function
by:
public virtual void clear(int c)
{
//screen.Clear(c);
DrawFilledRectangle(0, 0, width, height, c);
}
Also replace init function by:
public void init()
{
screen.SetGraphicsMode(VGAScreen.ScreenSize.Size320x200, VGAScreen.ColorDepth.BitDepth8);
width = screen.PixelWidth;
height = screen.PixelHeight;
clear(0);
}
Which is much faster. Good luck in creating your OS :)

UILabel with padding in Xamarin.iOS?

I'm trying to create a UILabel with padding in my Xamarin.iOS app. The most popular solution in native Objective-C apps is overriding drawTextInRect:
- (void)drawTextInRect:(CGRect)rect {
UIEdgeInsets insets = {0, 5, 0, 5};
return [super drawTextInRect:UIEdgeInsetsInsetRect(rect, insets)];
}
As simple as this seems, I can't quite figure out how to translate it to C#. Here's my best stab at it:
internal class PaddedLabel : UILabel
{
public UIEdgeInsets Insets { get; set; }
public override void DrawText(RectangleF rect)
{
var padded = new RectangleF(rect.X + Insets.Left, rect.Y, rext.Width + Insets.Left + Insets.Right, rect.Height);
base.DrawText(padded);
}
}
This does seem to move the label's text, but it doesn't resize the label.
I think the main issue is that I can't find the Xamarin equivalent of UIEdgeInsetsInsetRect.
Any suggestions?
The C# equivalent of the ObjC function UIEdgeInsetsInsetRect is a instance method of UIEdgeInsets named InsetRect and it's not identical to your RectangleF calculations (which is likely your problem).
To use it you can do:
public override void DrawText(RectangleF rect)
{
base.DrawText (Insets.InsetRect (rect));
}
You have to override both DrawText and TextRectForBounds.
If you don't override TextRectForBounds, the text will be clipped.
Actually, you override this method to compensate the space which is occupied by padding and ask iOS to draw the text in a bigger rectangle.
public partial class LabelWithBorder
: UILabel
{
private UIEdgeInsets EdgeInsets = new UIEdgeInsets(5, 5, 5, 5);
private UIEdgeInsets InverseEdgeInsets = new UIEdgeInsets(-5, -5, -5, -5);
public LabelWithBorder(IntPtr handle) : base(handle)
{
}
public override CoreGraphics.CGRect TextRectForBounds(CoreGraphics.CGRect bounds, nint numberOfLines)
{
var textRect = base.TextRectForBounds(EdgeInsets.InsetRect(bounds), numberOfLines);
return InverseEdgeInsets.InsetRect(textRect);
}
public override void DrawText(CoreGraphics.CGRect rect)
{
base.DrawText(EdgeInsets.InsetRect(rect));
}
}
Rather than overriding DrawText() in the subclass of UILabel, override it's intrinsic content size. This way auto-layout takes the padding into consideration. For example here's my derived class of UILabel:
public class PaddedLabel : UILabel
{
private readonly float _top;
private readonly float _left;
private readonly float _right;
private readonly float _bottom;
public PaddedLabel(float top, float left, float right, float bottom)
{
_top = top;
_left = left;
_right = right;
_bottom = bottom;
}
public override CGSize IntrinsicContentSize => new CGSize(
base.IntrinsicContentSize.Width + _left + _right,
base.IntrinsicContentSize.Height + _top + _bottom
);
}
I have created a generic Padding UIView class that wraps any IOS UI element that is derived from UIView.
Basically it nests the desired UIView into another view and takes care of all the padding work.
usage:
var myPaddedView = new PaddedUIView<UILabel>();
myPaddedView.Frame = TheActualFrame;
myPaddedView.Padding = 15f
myPaddedView.NestedView.Text = "Hello padded world"; // all the label Properties are available without side effects
Here is the class:
public class PaddedUIView<T>: UIView where T : UIView, new()
{
private float _padding;
private T _nestedView;
public PaddedUIView()
{
Initialize();
}
public PaddedUIView(RectangleF bounds)
: base(bounds)
{
Initialize();
}
void Initialize()
{
if(_nestedView == null)
{
_nestedView = new T();
this.AddSubview(_nestedView);
}
_nestedView.Frame = new RectangleF(_padding,_padding,Frame.Width - 2 * _padding, Frame.Height - 2 * _padding);
}
public T NestedView
{
get { return _nestedView; }
}
public float Padding
{
get { return _padding; }
set { if(value != _padding) { _padding = value; Initialize(); }}
}
public override RectangleF Frame
{
get { return base.Frame; }
set { base.Frame = value; Initialize(); }
}
}
The correct way to do this seems to have slightly changed since the original answer was given, and it took me awhile to figure out the new correct syntax. Here it is for anyone else who stumbles across this. This code would put padding of 5 on both the left and right sides of the view. This is in Xamarin.iOS
public override void DrawText(CGRect rect)
{
rect.X = 5;
rect.Width = rect.Width - 10; // or whatever padding settings you want
base.DrawText(AlignmentRectInsets.InsetRect(rect));
}
poupou's solution marked as the best answer doesn't work. I found another way to add padding to label.
public class PaddedLabel : UILabel
{
public PaddedLabel(IntPtr intPtr) : base(intPtr)
{
TextAlignment = UITextAlignment.Center;
}
public override CGSize IntrinsicContentSize
{
get
{
var size = base.IntrinsicContentSize;
return new CGSize(size + 16, size);
}
}
}

Accessing and setting the instance variable of one class from another class

I currently have a class called:
public class HeatmapComponent : GH_Component
I also have another class called:
public class HeatMap
Inside the Heatmap class I have two instance variables declared as:
public int _width;
public int _height;
I would like to be able to access and set the _width and _height variables from the HeatmapComponent class. I know this is a scope issue, but, I am a bit confused as to what needs to be done.
In my HeatmapComponent class, this was what I had in mind:
this._width = width; // width is declared somewhere in this class
this._height = height; // height is same as above
I apologize beforehand if this is a stupid question. Please let me know if I am missing code snippets. I'll be happy to provide.
You want to set the values of those two fields? They are readonly. You can do that only in the constructor.
public class HeatMap
{
private readonly int _width;
private readonly int _height;
public HeatMap(int wid, int hei)
{
_width = wid;
_height = hei;
}
}
And, as it is with passing things through constructor's params, you can use/provide them only when building a new instance. That's why they are called constructor and readonly fields:
public class HeatmapComponent
{
private int widthOfMap;
private int heightOfMap;
void createMapAndDoSomething()
{
var hmap = new HeatMap(widthOfMap, heightOfMap);
hmap.thing();
}
}
If you don't want to create a new HeatMap, and if you want to be able to set the width/height from some 'external' place at any point in time, then:
they cannot be readonly
some public way of changing them must exist
For example:
public class HeatMap
{
private int _width;
private int _height;
public void SetSize(int wid, int hei)
{
_width = wid;
_height = hei;
}
}
public class HeatmapComponent
{
private int widthOfMap;
private int heightOfMap;
private HeatMap oldMap;
void changeTheSizes()
{
oldMap.SetSize(widthOfMap, heightOfMap);
}
}
Or sometimes even better, use properties:
public class HeatMap
{
private int _width;
private int _height;
public int Width { set { _width = value; } }
public int Height { set { _height = value; } }
}
public class HeatmapComponent
{
private int widthOfMap;
private int heightOfMap;
private HeatMap oldMap;
void changeTheSizes()
{
oldMap.Width = widthOfMap;
oldMap.Height = heightOfMap;
}
}
Before I answer your question, you have one major, major issue: readonly. That means that the value of the variable cannot be changed once the object is created. By anyone. Period.
Now, you have a couple ways to do this. The first is to use properties like Snorre said. In effect, you'd get this:
public class HeatMap
{
public int Width { get; set; }
public int Height { get; set; }
}
public class HeatMapComponent
{
private HeatMap myHeatMap; // Must have a reference to the object you want to change!
public void SomeMethod()
{
myHeatMap.Width = 10;
}
}
Now, the obvious downside here is that ANYONE can change the properties of HeatMap. If for some reason you really, really want to make HeatMap's width and height editable only by the HeatMapComponent, you can make HeatMapComponent an inner class, like this:
public class HeatMap
{
private int width;
private int height;
public class HeatMapComponent
{
public HeatMap myHeatMap;
public void SomeMethod()
{
myHeatMap.width = 10;
}
}
}
however, I would strongly advise you to rethink what you're trying to do. Public inner classes are actually quite rare, in my experience, as they can violate OOP principles easily. A different application design may suit you better.
Couple of things:
readonly keyword makes anything settable only in the constructor. Example:
class XYZ
{
private readonly int x;
public XYZ()
{
x = 10; //works
}
public void SomeMethod()
{
x = 100; //does not work since it is readonly
}
}
Then there's the various access modifiers: private is only accessible in the class itself, protected is accessible in inherited classes and public is accessible anywhere. Internal is accessible within the same assembly.
public class HeatMapComponent
{
HeatMap _map;
public HeatMapComponent()
{
_map = new HeatMap();
}
public void SomeMethod()
{
_map.Width = 10; //should work if Width is public and not readonly and if _map was initialized already, ie not null
}
}
This sounds like a homework question, and the problem is you are not understanding the lesson.
Here's a way to create your HeatMap class. It contains an overload so you can either set the Width and Height in the constructor or via a Set method:
public class HeatMap {
public HeatMap() {
Width = 0;
Height = 0;
}
public HeatMap(int width, int height) {
Width = width;
Height = height;
}
public void Set(int width, int height) {
Width = width;
Height = height;
}
public int Width { get; private set; }
public int Height { get; private set; }
}
To use this in your HeatmapComponent class, you only need to create an instance of your HeatMap. Here are two ways of doing that:
public HeatmapComponent() {
}
public void Test1(int width, int height) {
var hm = new HeatMap(width, height);
Console.WriteLine("Width: {0}, Height: {1}", hm.Width, hm.Height);
}
public static void Test2(int width, int height) {
var hm = new HeatMap();
hm.Set(width, height);
Console.WriteLine("Width: {0}, Height: {1}", hm.Width, hm.Height);
}
Be sure you understand what is going on, though.

Is this efficient use of the is and as operator in a DrawableGameComponent?

I'm learning to use the as operator, and my goal was to create an option window (non windows form) that can:
Have options added to it (for flexibility, in case I want to use if statements to add menu items)
Be able to display text, textures, or a class (using the classes draw function)
Be controlled through the host GameState
I still haven't added the options for indicating an item is selected, my apologies for not posting a complete work. I also have not sorted the code into regions yet. Sorry again!
Is my code (particularly the draw function) properly using the is and as operators properly, from a performance and readability (non spaghetti code) standpoint?
public class OptionWindow : DrawableGameComponent
{
public Dictionary<int, Option> options;
int selectedOption;
bool windowLoops;
Rectangle drawRectangle;
int spacer;
int totalItemHeight;
SpriteFont sf;
SpriteBatch sb;
public Rectangle DrawRectangle
{
get { return drawRectangle; }
set { drawRectangle = value; }
}
public int SelectedOption
{
get { return selectedOption; }
set
{
if (windowLoops)
{
if (selectedOption >= options.Count())
selectedOption = 0;
if (selectedOption < 0)
selectedOption = options.Count() - 1;
}
else
{
if (selectedOption >= options.Count())
selectedOption = options.Count() - 1;
if (selectedOption < 0)
selectedOption = 0;
}
}
}
public OptionWindow(Game game, bool windowLoops, SpriteFont sf, Rectangle drawRectangle)
: base(game)
{
options = new Dictionary<int, Option>();
this.windowLoops = windowLoops;
this.sf = sf;
DrawRectangle = new Rectangle(drawRectangle.X, drawRectangle.Y, drawRectangle.Width, drawRectangle.Height);
}
public void Add(object option, bool selectable, bool defaultSelection, int height)
{
options.Add(options.Count(), new Option(selectable, option, height));
if (defaultSelection)
SelectedOption = options.Count() - 1;
UpdatePositions();
}
public void UpdatePositions()
{
UpdateTotalItemHeight();
if (options.Count() - 1 != 0)
spacer = (drawRectangle.Height - totalItemHeight) / (options.Count() - 1);
for (int i = 0; i < options.Count(); i++)
{
if (i == 0)
options[i].Position = new Vector2(drawRectangle.X, drawRectangle.Y);
else
{
options[i].Position = new Vector2(
drawRectangle.X,
options[i - 1].Position.Y + options[i - 1].Height + spacer);
}
}
}
public void UpdateTotalItemHeight()
{
totalItemHeight = 0;
for (int i = 0; i < options.Count(); i++)
{
totalItemHeight += options[i].Height;
}
}
protected override void LoadContent()
{
sb = new SpriteBatch(GraphicsDevice);
base.LoadContent();
}
public override void Draw(GameTime gameTime)
{
for (int i = 0; i < options.Count(); i++)
{
if (options[i].OptionObject is string)
sb.DrawString(sf, options[i].OptionObject as string, options[i].Position, Color.White);
if (options[i].OptionObject is Texture2D)
sb.Draw(options[i].OptionObject as Texture2D,
new Rectangle(
(int)options[i].Position.X,
(int)options[i].Position.Y,
options[i].Height,
(options[i].Height / (options[i].OptionObject as Texture2D).Height) * (options[i].OptionObject as Texture2D).Width),
Color.White);
if (options[i].OptionObject is DisplayObject)
(options[i].OptionObject as DisplayObject).Draw(gameTime);
}
base.Draw(gameTime);
}
}
public class Option
{
bool selectable;
object optionObject;
int height;
Vector2 position;
public bool Selectable
{
get { return selectable; }
set { selectable = value; }
}
public object OptionObject
{
get { return optionObject; }
set { optionObject = value; }
}
public int Height
{
get { return height; }
set { height = value; }
}
public Vector2 Position
{
get { return position; }
set { position = value; }
}
public Option(bool selectable, object option, int height)
{
Selectable = selectable;
OptionObject = option;
Height = height;
}
}
It is never adviseable to use is and then as. The usual way to go would be to either of the following:
just use is (if you just want to know the type without subsequent casting)
assign the result of as to a variable and check whether that variable is (not) null
The code analysis tool FxCop helps you find any spots in your code that use is and then as and warns you because of performance concerns.
Note however that a better approach altogether might be to declare your OptionObject property as some abstract class with a Draw method. You could then derive a subclass for strings, one for Texture2D instances and another one for DisplayObject instances and just call Draw in your OptionWindow.Draw method. This would leave the decision which actual drawing operations to execute up to built-in polymorphism features of the framework.

Overriding properties doesn't work

My class Ellipse should inherit from my class Shape but I get this error message:
Error 1 'ConsoleApplication3.Ellipse' does not implement inherited abstract member 'ConsoleApplication3.Shape.Perimeter.get'
I also get the error message that I'm hiding Area, a property in Ellipse.
Can anyone help me please?
My shape class looks like this:
public abstract class Shape
{
//Protected constructor
protected Shape(double length, double width)
{
_length = length;
_width = width;
}
private double _length;
private double _width;
public abstract double Area
{
get;
}
And my ellipse class is:
class Ellipse : Shape
{
//Constructor
public Ellipse(double length, double width)
:base(length, width)
{
}
//Egenskaper
public override double Area
{
get
{
return Math.PI * Length * Width;
}
}
}
You need to use the override modifier on the Area and Perimeter properties in your Ellipse class, e.g.
public override double Area { get; }
public override double Perimeter { get; }
A tip for you in Visual Studio, put the cursor inside the text 'Shape' (in your ellipse class) and press Ctrl + .. This should add stubs for members you haven't implemented
May be this is what you after as you have not declared Length , Width any where in your Ellipse class so you might be getting compilation errors, to compile this you need enhance visibility of _length and _width properties of your base class Shape.
public abstract class Shape
{
//Protected konstruktor
protected Shape(double length, double width)
{
_length = length;
_width = width;
}
// have these variables protected since you instantiate you child through the parent class.
protected double _length;
protected double _width;
public abstract double Area
{
get;
}
}
class Ellipse : Shape
{
//Konstruktor
public Ellipse(double length, double width)
: base(length, width)
{
}
//Egenskaper
public override double Area
{
get
{
// use the variable inherited since you only call the base class constructor.
return Math.PI * _length * _width;
}
}
}

Categories

Resources