How a function can be automatically called upon a variable change? - c#

I have a class consisting of variable members and a function member. The variable member occasionally changes. I want the function to be called automatically upon the variable changes. In other words, how can I tie the variables inside a class?
class line
{
double x, y; // The poition of the lind end. The line starts at the origin (0,0)
double l; // The length of the line
void length()
{
l = Math.sqrt(x*x+y*y);
}
}
In example above, I need the length to be updated when x and y change.

Make your variables into properties, then put your functions in the set accesors.
class line
{
double _x, _y;
double x
{
get { return _x; }
set
{
_x = value;
length();
}
}
double y
{
get { return _y; }
set
{
_y = value;
length();
}
}
double l; // The length of the line
void length()
{
l = Math.Sqrt(_x * _x + _y * _y);
}
}

If you define properties, on your class, you can make X and Y autoprops, then make a read-only property L that is calculated from these values:
public class Line //class names should be Capitalized
{
public double X{ get; set; } //prop names should be Capitalized
public double Y{ get; set; }
public double L{
get{
return Math.Sqrt(X * X + Y * Y);
}
}
}

you can you properties
int x
int X {
get { return x; }
set { x = value; YouMethod();}
}

You can achieve pretty similar behavior using calculated property like
double Length
{
get { return Math.sqrt(x*x+y*y); }
}
The only caveat is that calculation is performed upon each call to Length even if x and y haven't changed.
You can encapsulate you x and y fields into properties and call length function from setter like
double X
{
get { return x; }
set
{
x = value;
length();
}
}
double Y
{
get { return y; }
set
{
y = value;
length();
}
}
and then change x and y ONLY via X and Y properties.

As BenJ noted, you can use properties.
Instead of declaring x and y as simple fields inside the class. You can declare them as properties the following way :
private double x;
public double X
get
{
return this.x;
}
set
{
this.x = value;
this.length()
//Above line will call your desired method
}

Related

c# encapsulation Get/ Set

looking for some clarification on Get / Set. I have this code which I use to create my objects..However I want to have some validation in with the length and width (both need to be greater than some number as example). I believe Get / Set is the way to go and I have used this when changing fields in an instance - but how do I do it at the Instantiation stage?
class Room
{
public Double dblLength;
public Double dblWidth;
public Room (Double _dblLength, Double _dblWidth)
{
dblLength = _dblLength;
dblWidth = _dblWidth;
}
Turn fields into properties; implement validation within corresponding set:
class Room
{
private Double m_DblLength;
private Double m_DblWidth;
public Room (Double _dblLength, Double _dblWidth) {
DblLength = _dblLength;
DblWidth = _dblWidth;
}
public Double DblLength {
get {
return m_DblLength;
}
set {
//TODO: validation here
if (value < 0)
throw new ArgumentOutOfRangeException("value");
m_DblLength = value;
}
}
public Double DblWidth {
get {
return m_DblWidth;
}
set {
//TODO: validation here
if (value < 0)
throw new ArgumentOutOfRangeException("value");
m_DblWidth = value;
}
}
Here's an example, based on Alex's comment. Personally I'd also get rid of the underscores and 'dbl' prefix, but I've left them in to match the question.
You can't return a failure message from a constructor, so throw an exception.
class Room
{
private Double dblLength;
private Double dblWidth;
public Room (Double _dblLength, Double _dblWidth)
{
if (_dblLength < _dblWidth)
{
throw new ArgumentException("length must be more than width");
}
dblLength = _dblLength;
dblWidth = _dblWidth;
}
}
This is appropriate if it indicates that the programmer using your class doesn't understand it. However if there is a good chance of this happening at run time, you might be better to have a 'hasError' flag in the object that prevents it from being saved, or doing whatever it does.
class Room
{
private Double dblLength;
private Double dblWidth;
public bool HasError {get;}
public Room (Double _dblLength, Double _dblWidth)
{
if (_dblLength < _dblWidth)
{
HasError = true;
}
dblLength = _dblLength;
dblWidth = _dblWidth;
}
public Save()
{
if (HasError) return;
// Otherwise do the save;
}
}
If your class is immutable, the easiest is:
class Room
{
public double Length { get; }
public double Width { get; }
public Room(double length, double width)
{
// Validation here, for instance throw exception if length <= 0
Length = length;
Width = width;
}
}
Using C# 6's readonly auto properties.
You can change the fields into properties. When you have changed the fields into properties you can then validate the value which will be set to the according property and if it does not meet the requirements you can throw an exception.
Example:
class Room
{
private double _dblLength;
private double _dblWidth;
public double DblLength {
get
{
return _dblLength;
}
set
{
//TODO -> Do validation
//the keyword value represents the value that you want to pass to the property
if(value < 0)
{
throw new ArgumentOutOfRangeException("message");
}
_dblLength = value;
}
}
public double DblWidth
{
get
{
return _dblWidth;
}
set
{
//TODO -> Do validation
//the keyword value represents the value that you want to pass to the property
if (value < 1)
{
throw new ArgumentOutOfRangeException("message");
}
_dblWidth = value;
}
}
public Room(Double _dblLength, Double _dblWidth)
{
DblLength = _dblLength;
DblWidth = _dblWidth;
}
}
Another good thing to do is if you want the properties to be set only when an instance is created(only through the constructor) you can make the setter private like so:
class Room
{
private double _dblLength;
private double _dblWidth;
public double DblLength {
get
{
return _dblLength;
}
private set
{
//TODO -> Do validation
//the keyword value represents the value that you want to pass to the property
if(value < 0)
{
throw new ArgumentOutOfRangeException("message");
}
_dblLength = value;
}
}
public double DblWidth
{
get
{
return _dblWidth;
}
private set
{
//TODO -> Do validation
//the keyword value represents the value that you want to pass to the property
if (value < 1)
{
throw new ArgumentOutOfRangeException("message");
}
_dblWidth = value;
}
}
public Room(Double _dblLength, Double _dblWidth)
{
DblLength = _dblLength;
DblWidth = _dblWidth;
}
}
This is possible because properties are just syntax sugar provided to us by C#. When this code is compiled the compiler will create two methods Get and Set for each property. Thus if you put an access modifier on the getter or setter the compiler will take that in mind and when it compiles the code, it will put the modifier which you have specified. However, if no specific modifier is specified the compiler will take the modifier of the property itself in the above case the Get method will be public and the Set method will be private. After compilation the code will look something like this:
class Room
{
private double _dblLength;
private double _dblWidth;
public Room(Double _dblLength, Double _dblWidth)
{
SetDblLength(_dblLength);
SetDblWidth(_dblWidth);
}
public double GetDblLength()
{
return _dblLength;
}
private void SetDblLength(double value)
{
if (value < 0)
{
throw new ArgumentOutOfRangeException("message");
}
_dblLength = value;
}
public double GetDblWidth()
{
return _dblWidth;
}
private void SetDblWidth(double value)
{
if (value < 0)
{
throw new ArgumentOutOfRangeException("message");
}
_dblWidth = value;
}
}

C# GetName() , GetArea() for custom Interface “IShape” and it's derived classes

I have a task :
There is an hierarchy: "Shape" - interface, "Triangle", "Circle", "Rectangle" - derived classes of "Shape", "IsoscelesTriangle" - derived class of "Triangle", "Square" - derived class of "Rectangle". "Shape" has methods: GetArea() - returns the area of a geometric shape, GetName() - returns the name of a geometric shape. For each derived class area and name can be determined. Console program demonstrates the principle of polymorphism using the output messages of name and area.
My main looks lie this:
try {
Problem1_2.IShape triangle2 = new Problem1_2.Triangle("triangle", 5, 10);
double triangle2Area = triangle2.GetArea();
string triangle2Name = triangle2.GetName();
Console.WriteLine($"Name={triangle2Name}, Area={triangle2Area}");
Problem1_2.IShape isoTriangle2 = new Problem1_2.IsoscelesTriangle("isosceles triangle", 2, 10);
double isoTriangle2Area = isoTriangle2.GetArea();
string isoTriangle2Name = isoTriangle2.GetName();
Console.WriteLine($"Name={isoTriangle2Name}, Area={isoTriangle2Area}");
Problem1_2.IShape circle2 = new Problem1_2.Circle("circle", 5);
double circle2Area = circle2.GetArea();
string circle2Name = circle2.GetName();
Console.WriteLine($"Name={circle2Name}, Area={circle2Area}");
Problem1_2.IShape rect2 = new Problem1_2.Rectangle("rectangle", 2, 10);
double rect2Area = rect2.GetArea();
string rect2Name = rect2.GetName();
Console.WriteLine($"Name={rect2Name}, Area={rect2Area}");
Problem1_2.IShape square2 = new Problem1_2.Square("square", 2);
double square2Area = square2.GetArea();
string square2Name = square2.GetName();
Console.WriteLine($"Name={square2Name}, Area={square2Area}");
} catch (Exception) {
Console.WriteLine("Critical error: Value cannot be negative");
}
my custom classes namespace looks like this:
interface IShape
{
string GetName();
double GetArea();
}
public class Triangle : IShape
{
protected double side;
protected double height;
protected string name;
public Triangle(string name, double side, double height)
{
if (side >= 0 && height >= 0)
{
this.side = side;
this.height = height;
}
else
{
throw new Exception("Critical error: Value cannot be negative");
}
}
protected Triangle(string name)
{
Name = name;
}
public string Name { get; }
public virtual string GetName()
{
return "Shape: " + Name;
}
public double GetArea()
{
double area = (side * height) / 2;
return area;
}
}
public class Circle : IShape
{
private double radius;
public Circle(string name, double radius)
{
if (radius >= 0)
{
this.radius = radius;
}
else
{
throw new Exception("Critical error: Value cannot be negative");
}
}
protected Circle(string name)
{
Name = name;
}
public string Name { get; }
public virtual string GetName()
{
return "Shape: " + Name;
}
public double GetArea()
{
double area = radius * radius * Math.PI;
return area;
}
}
public class Rectangle : IShape
{
protected double side1;
protected double side2;
public Rectangle(string name, double side1, double side2)
{
if (side1 >= 0 && side2 >= 0)
{
this.side1 = side1;
this.side2 = side2;
}
else
{
throw new Exception("Critical error: Value cannot be negative");
}
}
protected Rectangle(string name)
{
Name = name;
}
public string Name { get; }
public virtual string GetName()
{
return "Shape: " + Name;
}
public double GetArea()
{
double area = side1 * side2;
return area;
}
}
public class IsoscelesTriangle : Triangle
{
public IsoscelesTriangle(string name, double side, double height) : base(name, side, height) { }
public double GetArea()
{
return base.GetArea();
}
}
public class Square : Rectangle
{
private double side1;
public Square(string name, double side1) : base(name, side1, side1)
{
if (side1 >= 0)
{
this.side1 = side1;
}
else
{
throw new Exception("Critical error: Value cannot be negative");
}
}
public double GetArea()
{
double area = side1 * side1;
return area;
}
}
But for some reason my classes names gets "null" instead of name. and returns only "Shape: " instead of:
return "Shape: " + Name;
can someone help me to figure it out?
Change:
protected Triangle(string name)
{
Name = name;
}
public string Name { get; }
public virtual string GetName()
{
return "Shape: " + Name;
}
to:
const string Name = "Triangle";
public virtual string GetName()
{
return "Shape: " + Name;
}
(and much the same for Circle etc)
Your old code allowed the name to be passed in, which is unnecessary. Think about them as people - you don't tell someone their name, you ask them. Thus, the class is in the best position to know its own name - so a constant there is best.
When instantiating different kind of shapes, you are calling the base class constructor using base() and passing the proper parameters, but in the constructor definitions you are not setting the Name property, you need to set that or you can call the constructor which sets the Name property, for example:
public Triangle(string name, double side, double height)
{
Name = name; // note this
if (side >= 0 && height >= 0)
{
this.side = side;
this.height = height;
}
else
{
throw new Exception("Critical error: Value cannot be negative");
}
}
or more better would be to use this() to call the constructor which is setting the Name property as well which can be done like (as you have constructor available which sets the Name of a particular IShape instance):
public Triangle(string name, double side, double height) : this(name)
{
........
........
........
}
The same way you need to call the proper constructor of Circle as well which would set the Name property as well :
public Circle(string name, double radius) : this(name) // call the constrcutor which takes Name
{
if (radius >= 0)
{
this.radius = radius;
}
else
{
throw new Exception("Critical error: Value cannot be negative");
}
}
and lastly do it for the Rectangle class as well:
public Rectangle(string name, double side1, double side2) : this(name)
{
........
........
........
}
The line this(name) will cause the constructor of Rectangle , Circle etc single parameter constructor to be called which is setting the Name property for the object which is getting instantiated.
Hope it helps!
Look at the Triangle class which implements the IShape interface. This mean the class must implement the GetName and GetArea methods. The Triangle class has properties of side1, height and name.
The “first” constructor takes the string, name, side and height variable, checks the side and height for greater than zero then sets the properties for those variables. PROBLEM: the name variable never gets set in this constructor. Below this appears to be another constructor for this…, which is unnecessary. Simply set the name in the original constructor, as you should be doing anyway. So, you can get rid of the protected Triangle(string name) constructor, along with the Name getter. All you need are the two methods for the IShape interface. Triangle class below:
public class Triangle : IShape {
protected double side;
protected double height;
protected string Name;
public Triangle(string name, double side, double height) {
if (side >= 0 && height >= 0) {
this.side = side;
this.height = height;
Name = name;
} else {
throw new Exception("Critical error: Value cannot be negative");
}
}
public string GetName() {
return Name;
}
public double GetArea() {
double area = (side * height) / 2;
return area;
}
}
Moving on to the Circle, and Rectangle classes you can see the same problems: name is not set in the original constructor. Similar changes as above should fix this. Moving on to the other two classes IsoscelesTriangle which inherits from the Trangle class and Square which inherits from the Rectangle class.. In these classes you need to keep in mind that since you are inheriting from the other classes… they hold most of the variables we need, so we only need to initialize the base, then implement the GetArea() method if different. Since the GetArea methods are the same as the base… there is no need to implement them as the base already implements them. If they are different, then you would override the GetArea method for that class.
public class IsoscelesTriangle : Triangle {
public IsoscelesTriangle(string name, double side, double height) : base(name, side, height) { }
}
public class Square : Rectangle {
public Square(string name, double side1) : base(name, side1, side1) { }
}
Hope this makes sense.

Is there a way for a property to set its backing value?

I have a property, and I want it to set another property whenever it's being set. For example:
private double Bpm
{
set
{
<myself> = value;
_bps = <myself> / 60;
}
get
{
return <myself>;
}
}
What I actually did is the following, because I couldn't find another way:
private double _bpm;
private double _bps;
private double Bpm
{
set
{
_bpm = value;
_bps = _bpm / 60;
}
get
{
return _bpm;
}
}
I find it not elegant, having two private members Bpm and _bpm. I can also have a SetBpm method, but I want to know if this is achievable with properties.
A property is just a pair of methods, really - and if you use an automatically-implemented property, the compiler implements them for you and creates a field. You want one field - because you've only got one real value, and two views on it - so you can either get the compiler to create that field for you automatically by using an automatically-implemented property, or you can declare it yourself. I'd use an automatically-implemented property, personally. Then you calculate the other property based on the original. You can either make that a read-only property, or make it read-write.
For example, as a read-only version:
public double BeatsPerSecond { get; set; }
public double BeatsPerMinute { get { return BeatsPerSecond * 60; } }
Or in C# 6:
public double BeatsPerSecond { get; set; }
public double BeatsPerMinute => BeatsPerSecond * 60;
For a read-write version:
public double BeatsPerSecond { get; set; }
public double BeatsPerMinute
{
get { return BeatsPerSecond * 60; }
set { BeatsPerSecond = value / 60; }
}
You could decide to make BeatsPerMinute the "stored" one instead, should you wish, and just change the property calculation.
My preferred approach would be to expose two public properties that update each other's backing fields. If your properties are read more frequently than they are updated, this would avoid repeatedly performing a multiplication or division operation on each read.
private double _bpm;
private double _bps;
private double Bpm
{
get
{
return _bpm;
}
set
{
_bpm = value;
_bps = value / 60;
}
}
private double Bps
{
get
{
return _bps;
}
set
{
_bps = value;
_bpm = value * 60;
}
}
Actually using properties are in public mode, so you can change your property to a value like below:
private double Bpm;
private double Bps
{
get
{
return Bpm / 60;
}
}
With thanks to #Farhad Jabiyev.

Call RaisedPropertyChanged for Parent Class when Child Property Changes

Structure of Program
Currently I am using the MVVMLight 4.1 framework in my application.
I have a view model XViewModel which wraps around an instance of XClass, X. X contains many properties such as S. I also have another instance of XClass in another ViewModel.
ViewModel
public XViewModelClass XViewModel : ViewModelBase
{
public XClass X
{
get
{
return x;
set
}
if(value == x)
{
return;
}
var oldValue = x;
x = value;
RaisePropertyChanged(XPropertyName, oldValue, x, true)
}
}
private XClass x;
public const string XPropertyName = "X"
}
ViewModel2
public YViewModelClass YViewModel : ViewModelBase
{
public YViewModel()
{
Messenger.Default.Register<PropertyChangedMessage<XClass>>(this, message =>
{
X2 = message.NewValue
});
}
public XClass X2
{
get
{
return x2
set
}
if(value == x2)
{
return;
}
var oldValue = x2
x2= value;
RaisePropertyChanged(X2PropertyName)
}
}
private string x2;
public const string XPropertyName = "X2"
}
Model
public class X : ObservableObject
{
public string S
{
get
{
return s;
set
}
if(value == S)
{
return;
}
s = value;
RaisePropertyChanged(SPropertyName)
}
}
private string s;
public const string XPropertyName = "S"
}
Problem
How do I ensure that when any property in X changes (e.g. S is set to a different value), RaisePropertyChanged is called for X. It would be best if I don't have to send a property changed message for every property in my model.
The reason behind is that I have another instance of XClass, `X2' in another ViewModel and I want to keep both instances in sync.
Proximo,
Can you provide more information on what you are trying to accomplish by firing a PropertyChangedEvent for X when a child member is set? Typically in WPF you be concerned
only with raising that event for the property/backing field to which you are bound, in this case X.S. Is there a specific use case for being notified when a member of X is set outside of scenario I provided?

Use a struct as a multidimensional array index

I have a 3D array that I'm accessing this way Array(int x, int y, int z). What I would like to know, if it is possible to have a struct, that has xyz in it, so that I can use it this way: Array(struct xyz). If it is, then how?
The reason for why I would want this, is that it would be easier for me to read and write, and that it would be alot simpler and less error prone to write. Makes it easier to maintain the bigger picture.
I do know that I could make a class that has its own method, but since I have many classes and applying it to each one would make me quickly loose the readability, using the struct directly would be a better option if available.
Example:
public struct xyz
{
public int x, y, z;
public xyz(int X, int Y, int Z)
{
x = X;
y = Y;
z = Z;
}
}
private void Test()
{
int(,,) Array = new int()
{
{
{0,0},
{0,0},
},
{
{0,0},
{0,0},
}
};
xyz XYZ = new xyz(0,0,0);
Array[XYZ] = 1; // this instead of
Array[XYZ.x, XYZ.y, XYZ.z] = 1 // this
}
You could create your own array class that wraps a real array, and provides an indexer to do what you want:
class MyArray<T>
{
private T[,,] array;
public MyArray(int xSize, int ySize, int zSize)
{
array = new T[xSize,ySize,zSize];
}
public T this[XYZ xyz]
{
get { return array[xyz.x, xyz.y, xyz.z]; }
set { array[xyz.x, xyz.y, xyz.z] = value; }
}
}
You can easily achieve that by creating your own collection that can be accessed either by specifying all thee coordinates separately:
public T this[int x, int y, int z] { get { … } set { … } }
Or by your XYZ struct:
public T this[XYZ xyz] { get { … } set { … } }
You can't add that indexer to array, extension indexers are not possible. What you could do is to create two extension methods. Something like:
public static T Get<T>(this T[,,] array, XYZ xyz)
{
return array[xyz.X, xyz.Y, xyz.Z];
}
public static void Set<T>(this T[,,] array, XYZ xyz, T value)
{
array[xyz.X, xyz.Y, xyz.Z] = value;
}
And then use it like this:
int i = array.Get(xyz);
array.Set(xyz, 25);
Also, creating mutable structs, like you did, is considered worst practice in C#. They can be very confusing.
Completing the solution of #Andrew Cooper, if you also want to access that matrix normally you must add this methods (Look at the end of Andrew's code)
class MyArray<T>
{
private T[,,] array;
// Constructor
public MyArray(int xSize, int ySize, int zSize)
{
array = new T[xSize,ySize,zSize];
}
// Index with your own struct XYZ
public T this[XYZ xyz]
{
get { return array[xyz.x, xyz.y, xyz.z]; }
set { array[xyz.x, xyz.y, xyz.z] = value; }
}
// Normal index
public T this[int x, int y , int z]
{
get { return array[x, y, z]; }
set { array[x, y, z] = value; }
}
// Get dimensions
public int GetLength(int dim)
{
return array.GetLength(dim);
}
}

Categories