Abstract parameters and methods beginner - c#

I'm just doing some practice for my coding course. I've just started with abstraction so it's still a bit coonfusing for me. I've got this code and I've managed to assign values to the regular properties so far. I want to run an abstract property through a virtual method and have the result assigned to the property finally. The abstract method should be overridden on the second derived class but not the first.
Right now the result is that the BPM property has a value of 0 for both derived classes, though I'm not sure why.
public abstract class Music
{
protected string genre;
protected int bpm;
public string Genre //property
{
get
{
return genre;
}
set
{
genre = value;
}
}
public int Bpm //abstract property
{
get;
set;
}
public virtual int BPM(int b) //virtual method
{
this.bpm = b;
return b;
}
public Music(string genre, int bpm)
{
this.genre = genre;
this.bpm = BPM(bpm);
}
}
public class Techno : Music
{
public Techno(string genre, int bpm) : base(genre, bpm) { }
}
public class Dubstep : Music
{
public override int BPM(int b)
{
return base.BPM(b) / 2;
}
public Dubstep(string genre, int bpm) : base(genre,bpm) { }
}
//PROGRAM-------------------------------------------------------------
class Program
{
static void Main()
{
Techno t = new Techno("Techno", 130);
Dubstep d = new Dubstep("Dubstep", 140);
Console.WriteLine(t.Genre + " " + d.Genre);
Console.WriteLine(t.Bpm + " " + d.Bpm);
}
}

Original Answer
First of all, this:
public int Bpm //abstract property
{
get;
set;
}
Is not an abstract property. What you are looking at here is an Auto-implemented property. That is a property for which the compiler creates a hidden backing field.
Second, here:
Console.WriteLine(t.Bpm + " " + d.Bpm);
You use the property mentioned above… And nowhere else. It is never assigned, so it has its default value, which happens to be 0.
You see, you have a field protected int bpm; that you use in your method:
public virtual int BPM(int b) //virtual method
{
this.bpm = b;
return b;
}
You also set it in the constructor:
public Music(string genre, int bpm)
{
this.genre = genre;
this.bpm = BPM(bpm);
}
But that field has nothing to do with the aforementioned property.
To reiterate bpm and Bpm are unrelated. I suppose I should also mention that C# is case sensitive.
Extended answer
So how would I make 'Bpm' and 'bpm' match, like 'Genre' and 'genre' match?
You have implemented the Genre property with a backing field genre:
public string Genre //property
{
get
{
return genre;
}
set
{
genre = value;
}
}
This is similar to what the compiler does for Bpm. The only difference is that you don't get to access the Bpm backing field.
I'll throw you a curve ball, and say that you can implement Genre the way you implemented Bpm and it would work. This is what you would do:
Remove the backing field genre.
Make Genre auto-implemented: public string Genre { get; set; }.
Have the constructor set the property Genre = genre;.
As a result, you will see that your code is simpler and shorter. That is the point of auto-implemented properties.
So, no, being an auto-implemented property is not preventing Bpm to work. The problem is that you are using a field bpm that has nothing to do with it.
Instead of writing to the unrelated field, you can write to the property from your constructor, for example:
public Music(string genre, int bpm)
{
Genre = genre; // Set Genre property
Bpm = bpm; // Set Bpm property
}
I want to run an abstract property through a virtual method and have the result assigned to the property finally
If I understand correctly, you expect Dubstep d = new Dubstep("Dubstep", 140); to have Bpm with the value 80. Right?
So, we want all writes to pass through the method. This is how you do that:
public abstract class Music
{
private int bpm;
public Music(string genre, int bpm)
{
Genre = genre;
Bpm = bpm;
}
public int Bpm
{
get => bpm;
set => bpm = BPM(value);
}
public string Genre { get; set; }
public virtual int BPM(int b) //virtual method
{
return b;
}
}
Here, Bpm is no longer auto-implemented. It will read and write the field pbm.
Also, Genre is auto-implemented. I made it so because we don't need to do anything special with it.
Now, every time the property is set, this will run bpm = BPM(value). Which will call the virtual method, which Dubstep overrides, resulting in the desired behavior.
To be clear, this code:
public int Bpm
{
get => bpm;
set => bpm = BPM(value);
}
Is the same as this code:
public int Bpm
{
get
{
return bpm;
}
set
{
bpm = BPM(value);
}
}
It is just a short-hand to write less code… Which bites me in the back, because I got to explain it. See Expression-bodied members (C# programming guide). Don't let the syntax confuse you.

Related

C# get/set inheritance?

I am not sure this is syntactically possible. If I have duplicate logic that would go in a getter/setter. Is there a way for a variable to inherit that pattern instead of re-typing the code.
private int basicVar;
public int BasicVar
{
get { return basicVar; }
set
{
if (IsServer)
{
basicVar = value;
Debug.Log("The variable name is: " + nameof(BasicVar));
//Other code
}
}
}
private int turn
public int Turn
{
//Inherits from basicVar
}
I am not sure if such a thing is possible, I was just curious.
(If it is, how could I template the private variable?)
I could do this by making it its own class, but I would prefer to keep it a primitive.
As mentioned in the comments, when needing to build reusable behavior, the preferred approach is to encapsulate the behavior in functions that can be called instead of the getter/setter of the property itself. This allows you to clearly define your expected behavior and allows you to easily compose logic by calling other methods.
public class Test
{
public bool IsServer { get; set; }
public int BasicVar { get; set }
public int Turn { get; set; }
public void UpdateBasicVar(int updatedValue)
{
if (IsServer)
{
BasicVar = updatedValue;
Debug.Log("The variable name is: " + nameof(BasicVar));
//Other code
}
}
public void UpdateTurnAndBasicVar(int updatedValue)
{
Turn = updatedValue;
Debug.Log("The variable name is: " + nameof(Turn));
UpdateBasicVar(updatedValue);
}
}
This also helps prevent side effects in your code. Typically, when using properties, C# developers expect that interacting with that property ONLY affects that property. It is not expected that updating one property would also update another.
Consider the following example:
public class SideEffects
{
private int basicVar;
public int BasicVar
{
get { return basicVar; }
set
{
if (IsServer)
{
basicVar = value;
Debug.Log("The variable name is: " + nameof(BasicVar));
//Other code
}
}
}
private int turn;
public int Turn
{
get { return turn; }
set
{
turn = value;
BasicVar = value;
}
}
}
while this is essentially functionally equivalent to the previous method-based example, it is no longer self-documenting. There is no way to determine from the public contract of the class that updating Turn will also update BasicVar, which is considered a side effect.

How to set property via setter

I have been taught in school about C#. We did some basic stuff like loops, if etc.
Now we do more about OOP. Teacher said us something about auto-implemented-property and I find this feature as great. But I am curious how can I set value of property via method.
When we didn't know auto-implemented-property. We always did a method to set or get value of class.
But when I use auto-implemented-property I do not see any methods to get or set value of class instance. So how can I set the value of some property of class when I can set the value only via constructor. I want to know that, because when property is private I can set it only via constructor, which is not a problem, but what I can do when I want to set value via Console.Readline(); ?
namespace _001_dedicnost
{
class Car
{
int Size { get; set; }
}
class Program
{
static void Main(string[] args)
{
Car car1 = new Car(5);
// but the following line wont work
car1.Set(51);
}
}
}
Your class Car have PRIVATE property Size, so u cant't have access to it from your code, only from class CAR
If u want to set value to this property, u have to declare it PUBLIC:
class Car
{
public int Size { get; set; }
}
static void Main(string[] args)
{
Car car1 = new Car();
car1.Size = 1;
}
When you put the property on the left-hand side of an expression, the set method is automatically called on it with the right-hand side of the expression as the value.
So car1.Size = 51 is like calling the expanded setter for the Size property with value being 51.
This
public class Point {
public int X { get; set; } = 0;
}
is equivalent to the following declaration:
public class Point {
private int __x = 0;
public int X { get { return __x; } set { __x = value; } }
}
This means you have "couple of 'methods' under c sharp compilator which called using '=' sign"
Point p = new Point();
p.X = 10; //c# compiler would call something like p.__set_X(10)
int i = p.X; //c# compiler would call something like int i = p.__get_X();
Read more about auto-properties https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/classes#automatically-implemented-properties
Btw I dont recommend to use it - it breaks readability and refactobility of code ;(
If the class is a simple anemic model (without logic), set the property as public, and it will work.
If you want to control the invariants (business rules), you'd want to have a public Size { get; private set; } with a public void SetSize(int size) { /* ... */ } which contains your business rules.
Here are three 'patterns' normally used in C#:
// Anemic domain model (simple entity)
public class Car
{
public int Size { get; set;}
}
// Domain model with business rules
public class Car
{
public int Size { get; private set; }
public void SetSize (int size)
{
// check to make sure size is within constraints
if (size < 0 || size > 100)
throw new ArgumentException(nameof(size));
Size = size;
}
}
// Value object
public class Car
{
public Car (int size)
{
// check constraints of size
Size = size;
}
public int Size { get; }
}

How to restrict access of a nested class's Property setter to the outer class only?

Is there an access modifier, or combination thereof, to restrict access to an outer class only?
For the Position property of nested class PanelFragment below, I would like only the containing class ViewPagerPanels to be able to set it (via the setter, I realize this could be done through a constructor parameter also).
public class ParcelView : MXActivityView<ParcelVM>, ViewPager.IOnPageChangeListener, IFragmentToViewPagerEvent
{
private ViewPagerPanels _pagerPanels;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
_pagerPanels = new ViewPagerPanels(5); // 5: magic number, put int constant
_pagerPanels[0] = new ViewPagerPanels.PanelFragment(typeof(ViewA));
// ...
}
private class ViewPagerPanels
{
public class PanelFragment
{
public Fragment Fragment { get; set; }
// ?? - access modifer for set
public int Position { get; private set; }
}
public readonly int PANEL_COUNT;
private PanelFragment[] _panels;
public ViewPagerPanels(int count)
{
PANEL_COUNT = count;
_panels = new PanelFragment[PANEL_COUNT];
}
public PanelFragment this[int i]
{
get
{
return _panels[i];
}
set
{
_panels[i] = value;
// !! - cannot access private property
_panels[i].Position = i;
}
}
}
}
No, it's not possible to do it directly. The most restrictive access modifier, private, already allows access from within the same class. Every other modifier further expands that access.
Every class, no matter if its nested, private or public, always has access to every single of its own declared members, with no chance of applyng restrictions to itself. The closest we can get is by using a readonly field (or a getter only property) that prevents the declaring class from modifying a variable outside the constructor. But for a read-write one, we're out of options.
There is a solution for this type of protection scenarios. But you should do the following changes;
1- Replace you concrete class with an interface or abstract class and expose this to outside world
2- Implement this interface with a concrete class
3- Control the creation of this class by a factory method
4- Set the property by casting the interface (or abstract class) to your private class type
Sample code changes
public interface IPanelFragment
{
Fragment Fragment { get; set; }
// ?? - access modifer for set
int Position { get; }
}
class PanelFragment : IPanelFragment
{
public Fragment Fragment { get; set; }
// ?? - access modifer for set
public int Position { get; set; }
}
private IPanelFragment[] _panels;
public IPanelFragment CreateFragment(Fragment fragment, int pos)
{
return new PanelFragment() { Fragment= fragment, Position = pos };
}
public IPanelFragment this[int i]
{
get
{
return _panels[i];
}
set
{
_panels[i] = value;
// !! - cannot access private property
((PanelFragment)_panels[i]).Position = i;
}
}
A possible workaround
public int Position { get; private set; }
public int InitPosition { set { Position = value; } }
or, depending on your philosophical perspective concerning getter-less Properties
public void InitPosition(int value) { Position = value; }

Override the property of an abstract class

I want to output the numberOfLegs of my tiger1 instance. But the output is 0 instead of my expected 4. Where is my mistake? Please help the tiger to get his legs back.
using System;
namespace AbstractProperty
{
class MainClass
{
static void Main(string[] args)
{
Tiger tiger1 = new Tiger();
int result = tiger1.NumberOfLegs;
Console.WriteLine(result);
Console.Read();
}
public abstract class Animal
{
public abstract int NumberOfLegs { get; set; }
}
public class Tiger : Animal
{
private int numberOfLegs;
public override int NumberOfLegs
{
get
{
return numberOfLegs;
}
set
{
numberOfLegs = 4;
}
}
}
}
}
EDIT: I think it is not good to use numberOfLegs = 4 in a Setter
As I see, the set accessor for NumberOfLegs is never called, thus numberOfLegs has the default value 0.
You could write a constructor and assign some value to NumberOfLegs, which would be assigned 4 anyway as you have hard-coded 4 in the set accessor, i.e. if you write your constructor like this:
public Tiger() {
NumberOfLegs = 10;
}
The set accessor would be called and assign 4 (not 10) to numberOfLegs. Perhaps you have mixed up the concepts a bit here :)
EDIT 1: If you now understand that assigning a hard-coded value in the setter was not that great, and you don't want to do anything special in the setter, it would be better to use the traditional approach for properties:
private int numberOfLegs;
public override int NumberOfLegs
{
get
{
return numberOfLegs;
}
set
{
numberOfLegs = value;
}
}
Or simply
public override int NumberOfLegs { get; set; }
which does the same thing as above.
And assign value to NumberOfLegs in the constructor:
public Tiger()
{
NumberOfLegs = 4;
}
The NumberOfLegs property setter is not called as you're not changing the value anywhere in your code. The int value is zero by default. You can do one of the following:
Define the default value of numberOfLegs variable when declaring it:
private int numberOfLegs = 4;
Define the numberOfLegs value in constructor of Tiger class:
public class Tiger : Animal
{
private int numberOfLegs;
public Tiger() {
numberOfLegs = 4;
}
// ...
}
You are doing it all wrong...
Don't provide a setter for numberOfLegs. Just provide a getter. And then set the number of legs in the constructor, or just set the field directly, like so:
public abstract class Animal
{
public abstract int NumberOfLegs { get; }
}
public class Tiger : Animal
{
private int numberOfLegs = 4;
public override int NumberOfLegs
{
get
{
return numberOfLegs;
}
}
}
The reason your code wasn't working was because you weren't calling the setter for Tiger.NumberOfLegs, but of course if you did so you'd realise how wrong it was:
Tiger tiger1 = new Tiger();
tiger1.NumberOfLegs = 100;
int result = tiger1.NumberOfLegs; // Set to 100, but now it's 4! Urk.

C# Errors and Headache >.< (MonoDevelop version2.8.2 for Unity 3d)

Ok so I have a problem :/ first off Im using C#.. Next, in the section where you see
public int BaseValue()
{
get{return _basevalue;}
set{_basevalue value; }
}
I get 3 Errors
1) Unexpected symbol `{'
2)Unexpected symbol `{' in class, struct, or interface member declaration
and
3) Parsing Error
and frankly its pissing me off -_- so does anyone know what the problem may be?
public class BaseStats {
private int _basevalue; //base value of this stat
private int _buffvalue; //amount needed to buff the stat
private int _expToLevel; //amount needed to move to the next level
private float _LevelModifier; //the modifier applied to the exp needed to raise the skill
public BaseStats()
{
_basevalue = 0;
_buffvalue = 0;
_expToLevel = 100;
_LevelModifier = 1.1f;
}
//Basic Setters and Getters
public int BaseValue()
{
get{return _basevalue;}
set{_basevalue value; }
}
public int BuffValue()
{
get{return _buffvalue; }
set{_buffvalue value; }
}
public int ExpToLevel()
{
get{return _expToLevel; }
set{_expToLevel.value; }
}
public float LevelModifier()
{
get{return _levelModifier; }
set{_levelModifier.value; }
}
private int CalculateExpToLevel()
{
return (int)(_expToLevel * _levelModifier);
}
public void LevelUp()
{
_expToLevel = CalculateExpToLevel();
_baseValue++;
}
public int AdjustedValue()
{
return _baseValue + _buffValue;
}
}
Properties do not have parentheses. Eliminate the () and fix your setter on what you intend to be properties. Eliminate the get/set on what you intend to be methods.
// this is a property
public int Foo
{
get { return foo; }
set { foo = value; }
}
// this is a method
public decimal Bar()
{
// do something and return a decimal
}
And note, as of C# 3, if your property is a simple get/set operation, you can use auto-implemented properties and eliminate the explicit backing variable.
public int Foo { get; set; }

Categories