class variables and properties with inheritance - c#

I'm confused about properties in C#, espacially with inheritance:
I have a Pokemon class as an example and want the stats to be protected to modify them in the subclasses (for example at level ups) and I want to read the stats from outside.
This would be the verbose way to do it:
// base class
abstract class Pokemon
{
// stats
protected int hp;
public int Hp {
get
{
return hp;
}
protected set
{
hp = value;
}
}
// other stats...
}
My Question is: Is there a short form for this? Something like:
// base class
abstract class Pokemon
{
// stats
public int Kp { get; protected set; }
// other stats...
}
Do these 2 classes work similarly?
I'm confused, because for public getters and setters you write:
// base class
abstract class Pokemon
{
// stats
public int Kp { get; set; }
// other stats...
}
And it works like:
// base class
abstract class Pokemon
{
// stats
private int kp;
public int Kp {
get
{
return kp;
}
set
{
kp = value;
}
}
// other stats...
}
Which one should I prefer?

My Question is: Is there a short form for this?
Yes exactly as you wrote it
Do these 2 classes work similarly?
Yes, in the first example you can additionally manipulate the field hp in the derived classes directly. (personally I don't see the point, you can also make it private )
Which one should I prefer?
That is difficult to say. If you need extra logic to validate the setting of the property use the first option.
private const int maxHP = 3000;
protected int hp;
public int Hp {
get
{
return hp;
}
protected set
{
// extra validation
if(value < maxHP)
hp = value;
else
hp = maxHP;
}
}
if you don't need it, don't use it

Related

Inherited method returning childs attributes doesnt work c#

I have two classes Taxi and Van. Lets say van1 is an instance of the Van. Whenever I run van1.ReturnNumOfPass(), it doesnt work properly.
I think it returns Taxi.num_of_pass instead. Is there any way to fix or do I have to write override the method? Thank you in advance
internal class Taxi
{
private string SPZ;
private int num_of_pas;
private int max_num_of_pas = 4;
public virtual int ReturnNumOfPas() => num_of_pas;
}
internal class Van : Taxi
{
private string SPZ;
private int num_of_pas;
private int max_num_of_pas = 2;
}
I tried to add this before the num_of_pass when returning it
You made num_of_pas as a private variable in each class - that means that they are independent variables.
If you want Van to use the same num_of_pas as Taxi then declare it as protected in Taxi and remove the declaration from Van. Like this:
internal class Taxi
{
protected int num_of_pas = 4;
public virtual int ReturnNumOfPas()
{
return num_of_pas;
}
}
internal class Van : Taxi
{
public Van()
{
num_of_pas = 8;
}
}
To test this, I ran this code:
Van van = new();
Console.WriteLine(van.ReturnNumOfPas());
The result was that 8 was output to the Console.
If I were writing more idiomatic C# then I would probably have expected something like this:
internal class Taxi
{
public int NumberOfPassengers { get; protected set; } = 4;
}
internal class Van : Taxi
{
public Van()
{
this.NumberOfPassengers = 8;
}
}
We would typically use properties to return values, not functions.

How to increase a derived class value

I am modelling a program that simulates driving and refueling cars and trucks. So this is what I have done so far:
public abstract class Vehicle
{
protected Vehicle(double fuelQuantity, double fuelConsumption)
{
this.FuelQuantity = fuelQuantity;
this.FuelConsumption = fuelConsumption;
}
public double FuelQuantity { get; protected set; }
public double FuelConsumption { get; protected set; }
public abstract string Drive(double distance);
public abstract void Refuel(double liters);
}
public class Car : Vehicle
{
public Car(double fuelQuantity, double fuelConsumption) : base (fuelQuantity, fuelConsumption)
{
}
public override string Drive(double distance)
{
}
public override void Refuel(double liters)
{
}
}
So, I want to increase the value of the fuel consumption of the cars with 0.9 liters (it's summer, so cars use air conditioners). Where this can be done? I don't want to do it in the constructor because I don't think it's okay.
This would be a good place to add a decorator.
Some pseudo code (not complete!) but hopefully you get the idea.
public class VehicleDecorator : Vehicle
public VehicleDecorator(Vehicle vehicle)
{
this.vehicle = vehicle;
}
public class VehicleWithAc : VehicleDecorator
public VehicleWithAc(Vehicle vehicle) : base(vehicle){}
public override double FuelConsumption {
get{
return base.FuelConsumption+0.9 } }
Then in your program, create your car and decorate it with a VehicleWithAc decorator
Program
var baseCar = new Car();
var summerDriver = new VehicleWithAc(baseCar)
I think the problem you have is that you're passing fuelConsumption as a single variable in to the constructor, thereby stating
This is the fuel consumption of the car, full stop.
As you've found out, working through the problem - fuel consumption isn't a static thing, it's dependant on other variables, such as whether the AC is on. Doug was getting close with his mention of the decorator, but I think it can be a little simpler, but more flexible.
I think you should still pass a fuel consumption figure in, and for simplicitys sake, we'll call it baseFuelConsumption. Remember, vehicles are usually graded on urban, and highway fuel consumptions as they are generally different, but for the purposes of this, we'll ignore it.
Leaving out distance travelled etc, we have:
public abstract class Vehicle
{
private readonly double _baseFuelConsumption;
protected double BaseFuelConsumption => _baseFuelConsumption;
protected Vehicle(double baseFuelConsumption) => _baseFuelConsumption = baseFuelConsumption;
public virtual double ActualFuelConsumption => BaseFuelConsumption;
}
So, how much extra fuel consumption does an AC use? Let's take Doug's answer as a base-point, and give that to our car....
public class Car : Vehicle
{
private const double _ACModifier = 0.9;
public Car()
:base(1)
{
}
public bool IsACOn { get; set; }
public override double ActualFuelConsumption
{
get
{
double consumption = base.ActualFuelConsumption;
consumption += IsACOn ? _ACModifier : 0;
return consumption;
}
}
}
Now, for the purposes of your simulation you can switch the AC on and off, over time, and measure the ActualFuelConsumption property over time.
If you want to use this stracture you have to set custom rules for properties.
public abstract class Vehicle
{
protected Vehicle(double fuelQuantity, double fuelConsumption)
{
this.FuelQuantity = fuelQuantity;
this._fuelConsumption = fuelConsumption;
this.FuelConsumption = fuelConsumption;
}
public double FuelQuantity { get; protected set; }
private double _fuelConsumption { get; set; }
public double FuelConsumption {
get { return _fuelConsumption; }
protected set {
_fuelConsumption = (_fuelConsumption + 0.9);
} }
public abstract string Drive(double distance);
public abstract void Refuel(double liters);
}
Because your class is abstract and you dont have no overridable in properties in your derived class you cant have access to base properties.You can use condition in set for example
public double FuelConsumption {
get { return _fuelConsumption; }
protected set {
if(Issummer)
{
_fuelConsumption = (_fuelConsumption + 0.9);
}else{ _fuelConsumption =_fuelConsumption;}
} }

C# Mock a Class With an Internal Property Setter

I am trying to build a unit test.
The class Position is implemented in a third party library. But for my unit test I need the Size property to be set to a specific value.
public class Position
{
private double _size;
private double Size
{
get
{
return _size;
}
internal set
{
_size = value;
}
}
}
I read this post: How do you create a unit-testing stub for an interface containing a read-only member?
but could not figure out how to make it work for me.
This is the class under test (just a simplified example). The posargument in the CalcPositionMetric() method must be of type Position:
public class PositionMetrics
{
public PositionMetrics()
{}
public double CalcPositionMetric(Position pos)
{
return 2 * pos.Size;
}
}
Here is a piece of my unit test:
using NUnit.Framework;
using NMock;
[TestFixture]
public class PositionUnitTests
{
[Test]
public void TestPosition()
{
Mock<Position> tmpPosMock = mFactory.CreateMock<Position>();
tmpPosMock.Expects.One.GetProperty(v => v.Size).WillReturn(7); /* !!! Exception !!! System.ArgumentException : mock object position has a getter for property Size, but it is not virtual or abstract */
/* Execute Test with tmpPositions*/
PositionMetrics pm = new PositionMetrics();
double result = pm.CalcPositionMetric(tmpPosMock.MockObject)
Assert.AreEqual(14, result);
}
}
But as you can see I get an exception. Could somebody help me to resolve this problem? Any other solutions are also welcome!
Cheers
Konstantin
New answer for the updated question I suggest you to introduce some kind of a proxy interface for that. See the code below:
interface IPosition {
int Size { get; }
}
class Position { //in 3rd party lib
public int Size {
get { return 5; }
}
}
class RealPosition : IPosition { //use this as your real object instead of using Position directly
private Position position;
public RealPosition(Position position) {
this.position = position;
}
public int Size {
get { return position.Size; }
}
}
class MockPosition : IPosition { //use this for testing
public int Size{ get; set; }
}
public class Program {
static void Main(string[] args) {
var pos = new MockPosition { Size = 7 };
Console.WriteLine(Calc(pos)); //prints 14
Console.ReadLine();
}
static int Calc(IPosition pos) { //change your method signature to work with interface
return pos.Size * 2;
}
}
Old answer If the class is not sealed you don't need any mocking libraries. Just use the new modifier for the required properties like this:
class Position {
public int Size { get { return 5; } }
}
class MockPosition : Position {
public new int Size { get; set; }
}
....
var mock= new MockPosition();
mock.Size = 7;
To use these items in some sort of list you'll have to cast them like this:
var items = new List<Position>();
for (int i = 0; i < 5; i++) {
items.Add(new MockPosition { Size = i });
}
foreach (var item in items.Cast<MockPosition>()) {
Console.Write("{0}\t", item.Size); //prints 0 1 2 3 4
}
If it is sealed and the property is not virtual than you'll have to use some other techniques, Moq (which I guess you are using) does not allow that

Assign multiple values to one object(?)

Note: I am somewhat of a beginner to C#.
I'm working on a little game that will have a bunch of different levels. Each level has its own class that contains variables (and other irrelevant code). Since I need to pass these values to the main class (my form) I have made them all into methods that returns the value I want (since I can't come up with a better solution). example:
class Level01
{
public int Boxes() { return 3; }
public int MaxPoints() { return 46; }
public int Health() { return 63; }
public int[,] SolidBoxes()
{
int[,] position = new int[Boxes(), Boxes()];
position[1, 1] = 1;
return position;
}
}
When I access these values from my form class I do
int boxes;
int maxPoints;
int health;
int[,] solidBoxes;
void readLevelData() //Starts each new level
{
//Reads the correct level
switch (levelNo)
{
case 1:
setValues(Lvl01.Boxes(), Lvl01.MaxPoints(), Lvl01.Health(), Lvl01.SolidBoxes());
break;
//The same case 2:, 3: for Level02,03..
}
}
void setValues(int getBoxes, int getMaxPoints, int getHealth, int[,] getSolidBoxes)
{
boxes = getBoxes;
maxPoints = getMaxPoints;
health = getHealth;
solidBoxes = getSolidBoxes;
}
I am aware that there's probably a million things in my code here that can be done better and I gladly listen if you have any suggestions, but the thing I wish to ask is:
How can I get all the values from each class using maybe just one name? Ex. Instead doing as I do now, is there a way so I can do something similar to this:
case 1:
setValues(Lvl01.Values);
break;
The problem here is in the setValues method, some of the levels has quite a lot of settings that I wish to use, but I doubt the method would want to take like 15 parameters, and I'm not sure what to do when some levels are not using settings that other levels use.
How should I change my code so I do not have to use every single value as a parameter?
You could use a Dictionary<int, Level> to lookup the object representing each level. Instead of the switch/case, you would do something like
Level level = myLevelDictionary[currentLevel];
That requires you change your classes from having one class per level, to one class that represents any level, e.g.:
class Level
{
public int Boxes { get; set; }
public int MaxPoints { get; set; }
public int Health { get; set; }
public int[,] SolidBoxes()
{
int[,] position = new int[boardSize, boardSize];
position[1, 1] = 1;
return position;
}
}
You would then populate your dictionary like
Dictionary<int, Level> myLevelDictionary = new Dictionary<int, Level>()
{
{ 1, new Level() { Boxes = 3, MaxPoints = 46, Health = 63 } },
// etc.
};
UPDATE
A note about abstract classes
You mention abstract classes in your comments. They are useful if all of your levels have some behavior in common, but some have specialized behavior too. They will often be used in games for things that can move in the game, e.g. something like
abstract class Character
{
// Something everyone has
public int HitPoints { get; set; }
// Something everyone does, but does differently
public abstract void Attack(Character target);
}
public class Fighter : Character
{
public int SwordDamage { get; set; }
public void Attack(Character target)
{
target.Damage(this.SwordDamage - target.PhysicalDamageResistance);
}
}
public class Mage : Character
{
public int MagicFireDamage { get; set; }
public int MagicColdDamage { get; set; }
public void Attack(Character target)
{
if (UseFireDamage()) // e.g. roll random chance that the mage uses a fire spell
{
target.Damage(this.SwordDamage - target.FireDamageResistance);
}
else
{
target.Damage(this.SwordDamage - target.ColdDamageResistance);
}
}
}
one way maybe to use a dictionary.
class Level01
{
Dictionary<string,int> values;
public level01()
{
values.Add("Boxes",3);
values.Add("MaxPoints",3);
values.Add("Health",3);
}
//indexer
public int this[string s] {get{return values[s];} set {values[s] = value;}}
}
and use like:
Level01 lv = new Level01();
somemethod(lv["Boxes"]); //passes 3 to some method
although really you would want to use Dictionary<string,object> and add some type checking and other things to make it work smoothly but hopefully you can get started with that

Get an object out of a mixed type collection

Hi I'm new to OOP and I need help on a little problem.
I used a collection called Monsters to store 3 types of object. Spiders, Farmers, Gollum(irrelevant).
My collection as an indexer but when I use it to get an object out of the collection the object is typeless but I really need to TypeCast my next opperation.
private void Form1_Load(object sender, EventArgs e)
{
CurrentOpponent Opponent = new CurrentOpponent();
Gollum myGollum = new Gollum();
AngryFarmer myFarmer = new AngryFarmer();
Ugly_Spider mySpider = new Ugly_Spider();
myMonsters.AddGollum(myGollum);
myMonsters.AddFarmer(myFarmer);
myMonsters.AddUgly(mySpider);
progressBar1.Increment(100);
progressBar2.Increment(100);
Monster myCurrentOpponent = Opponent.randomEncounter();
//textBox1.Text = (this is where i need the type for a cast)myCurrentOpponent.name
}
Here is the randomEncounter where i extract the object
class CurrentOpponent
{
public Monster randomEncounter()
{
Random _random = new Random();
int opp = _random.Next(4);
return myMonsters[opp];
}
And finally the indexer wich returns a monster (parent of all 3 monster types)
public Monster this[int xxx]
{
get
{
return (Monster)List[xxx];
}
}
Help would be really appreciated..!!
Thanks in advance
Ideally, AngryFarmer, Ugly_Spider and Gollum should all inherit from Monster:
public class AngryFarmer : Monster
{
// ...
}
// etc.
You could then just use a List<Monster>:
myMonsters = new List<Monster>();
myMonsters.Add(new AngryFarmer()); // works because AngryFarmer is a kind of Monster
This will allow you to use polymorphism.
you need to use interfaces...... IMonster..... IMonster then has a name
then make all your monsters implement IMonster
and just have a List of IMonsters
you may wanna try it by using interfaces also! have a look...
public interface IMonster
{
String Name { get; }
Int32 Health { get; set; }
}
public class Spider : IMonster
{
public Spider()
{
_health = 100;
}
public string Name
{
get { return "Spider"; }
}
private int _health;
public int Health
{
get { return _health; }
set { _health = value; }
}
}
public class Gollum : IMonster
{
public Gollum()
{
_health = 250;
}
public string Name
{
get { return "Gollum"; }
}
private int _health;
public int Health
{
get { return _health; }
set { _health = value; }
}
}
class Program
{
static void Main(string[] args)
{
List<IMonster> monsters = new List<IMonster>()
{
new Gollum(),
new Spider()
};
IMonster randomMonster = GetRandomMonster(monsters);
Console.WriteLine(randomMonster.Name + "/" + randomMonster.Health);
}
private static IMonster GetRandomMonster(List<IMonster> monsters)
{
//Your code for getting a random monster goes here!
throw new NotImplementedException();
}
}
I like very much this approach... Imagine you have an element on your game that initially is not exactly a monster. Say it is a random element on your game that after a given event it becomes a monster that your Hero (say a game like heroes of mighty and magic) have to fight with. If you decided to add this feature long time after you created the game, it would become harmful/difficult/risky to change it, as this element might have already be inheriting from another class. If you were using interfaces you would simply implement it on this entity and it would promptly be capable of behaving like any other IMonster in your game. It means that this random entity would be able to be passed as a param to the method Fight(IHero hero, IMonster monster);
Ideally, AngryFarmer, Ugly_Spider and Gollum should all inherit
from Monster
I have learn your problem like the problem in the Tetris game:
1/ You have Monsters like I have Shapes.
2/ Each kind of Monster have it own properties (Health, Magic Point,...) and behaviours (attack, run, cast spell,..) like the Blocks have properties (color, position, state,..) and
behaviours (go down, rotate right, rotate left,...)
In the scene of the game you want to random a Monster that have the specific properties and behaviours, like I want to random a Shape. If it is your problem you can try my code:
public abstract class CMonster
{
int _HP;
int _MP;
//..and something like this
public int HP
{
get { return this._HP; }
set { this._HP=value;}
}
public int MP
{
get { return this._MP; }
set { this._MP = value; }
}
public abstract void Run();
public abstract void Attach();
public abstract void CastSpell();
}
public class CUgly_Spider : CMonster
{
public CUgly_Spider()
{
this.MP = 100;//your value here
this.HP = 100;//your value here
}
public override void Attach()
{
//your implemetation here
}
public override void Run()
{
//your implemetation here
}
public override void CastSpell()
{
//your implemetation here
}
}
public class CGollum : CMonster
{
public CGollum()
{
this.MP = 100;//your value here
this.HP = 100;//your value here
}
public override void Attach()
{
//your implemetation here
}
public override void Run()
{
//your implemetation here
}
public override void CastSpell()
{
//your implemetation here
}
}
class Test
{
private void InitTheGame()
{
CMonster curMonster=null;
Random rnd = new Random();
//sample random
if ((rnd.Next() % 2) == 0)
{
curMonster = new CGollum();
}
else
{
curMonster = new CUgly_Spider();
}
curMonster.Run();//when (rnd.Next() % 2) == 0 then the Gollum is doing else the Ugly_Spider
curMonster.Attach();//when (rnd.Next() % 2) == 0 then the Gollum is doing else the Ugly_Spider
curMonster.CastSpell();//when (rnd.Next() % 2) == 0 then the Gollum is doing else the Ugly_Spider
}
}
I hope that can help you.

Categories

Resources