Best way to write multiple constructor overloads in C# - c#

I am learning C# and made a simple "Player" class. But I struggle having multiple overload.
Here's my best solution but I feel like it could be done simpler/better.
class Player : Entity
{
public Player() {
Name = "Player";
XP = 0;
LVL = 1;
XPToLvlUp = 10;
XpRank = 10;
}
public Player(string name) : this() {
Name = name;
}
public Player(string name, int _Hp, int _Mp) : this(name) {
HP = _Hp;
MP = _Mp;
}
public Player(string name, int _Hp, int _Mp, int _Xp, int _Lvl) : this(name, _Hp, _Mp) {
XP = _Xp;
LVL = _Lvl;
}
public Player(string name, int _Hp, int _Mp, int _Xp, int _Lvl, int XpByRank) : this(name, _Hp, _Mp, _Xp, _Lvl) {
XpRank = XpByRank;
}
//deleted code for better reading
private int XPToLvlUp;
private int XpRank;
public int XP;
public int LVL;
public string Name;
}
Is it good and if not please tell me why.
Thanks for your responses!

I think it's fine as is. One question to ask yourself: Are each of those methods actually likely to be called?
One option is to just let the programmer set those values after they've instantiated the class:
var myPlayer = new Player();
myPlayer.XP = 5;
However, there are situations where you really want all the info up front, so that may not be suitable.
Another option could be an options class that is passed to the ctor:
public class PlayerSettings
{
public Name = "Player";
public XP = 0;
public LVL = 1;
public XPToLvlUp = 10;
public XpRank = 10;
}
Then your ctors looks like this:
public Player() : this(new PlayerSettings())
{
}
public Player(PlayerSettings settings)
{
//Fill in appropriate variables here
}
That option would be called in this way:
var playerSettings = new PlayerSettings() { XP = 5 };
var myPlayer = new Player(playerSettings());
In the end, I'm not sure one is "better" than the other, it largely depends on your needs.

Your class is almost good and acceptable.
Short story: use Properties.
Long story:
First of all make or follow the naming rules, it will make your code more friendly to read. It's up to you, just a suggestion. For complex names consisting of multiple words you may use CamelCasedNames. And avoid shorten names for all types of data where it maybe useful. For example you may expand Lvl to Level but Xp to Experience will look as something odd. It's up to you too.
string name; // local Variable, first character lower cased
private string _name; // private Field, first character is lower cased with leading "_"
public string Name { get; set; } // public Property, first character is upper cased
I'll show you alternatives to overriden constructors and will follow the naming rules.
1) Default values for constructor (with a part of your class to keep it simple)
class Player
{
public Player(string name = "Player", int xp = 0, int level = 1)
{
Name = name;
Xp = xp;
Level = level;
}
// Properties instead of Fields
public int Xp { get; private set; } // restrict modification of the property outside of a class but reading is available
public int Level { get; private set; }
public string Name { get; set; }
}
2) Properties without constructor with default values
First Property purpose is restrict access to data to keep internal object data consistent. Even you make mistakes in the code. Good way to avoid some bugs.
Second property purpose is executing code while you're getting or setting one. For example, making properties dependent on each other to store less and only unique data.
class Player
{
public int Xp { get; private set; } = 0;
public int Level { get; private set; } = 1;
public string Name { get; set; } = "Player";
}
Usage
Player player = new Player() { Name = "KillerPWNZ", Level = 100, Xp = 999999 };
Bonus: Another Property feature
You can execute any code in get or set clause.
Let's assume that each next player's level require doubled amount of xp from previous but 2nd level requre 100 XP. And you decided to invoice to the 1st leveled player 1000 XP. Obviously you'll need to bump the Level few times. Assuming that Xp contains relative to Level value.
The invoice
player.Xp += 1000;
The Property with code
private int _xp = 0;
public int Level { get; private set; } = 1;
public int Xp
{
get => _xp; // same as: get { return _xp; }
set
{
_xp = value; // here value is keyword containing data you want to set
while (_xp >= GetXpPerLevel(Level))
{
_xp -= GetXpPerLevel(Level);
Level++;
}
while (_xp < 0 && Level > 1)
{
_xp += GetXpPerLevel(Level - 1);
Level--;
}
}
}
// helper method
private int GetXpPerLevel(int level)
{
if (level < 1) return 0;
// int result = 100;
// for (int i = 1; i < level; i++) result *= 2;
// return result;
// or the same with some binary shift magic :)
return 100 << (level - 1);
}

Related

How to randomly pick value from a list in Unity3D?

Suppose I have a list of Robot class [List< Robot> myList=new List< Robot>()]. Each Robot has a name and id depending on its colour. Now randomly pick values from the list and give an output of how many Robots of each colour are there on your list.
(N.B. Consider you have only 3 colored Robot[Yellow,green, red])
my code:
public class Test : MonoBehaviour
{
private void Start()
{
List<Robot> myList = new List<Robot>();
List<string> robotList = new List<string>();
robotList.Add("yellow");
robotList.Add("green");
robotList.Add("red");
int someNum = Random.Range(0, robotList.Count);
string robotNumber = robotList[someNum];
robotList.RemoveAt(someNum);
Robot robot;
int id = 0;
robot = new Robot(robotNumber, id);
Debug.Log(robot);
id++;
}
}
public class Robot
{
public string name;
public int id;
public Robot(string name, int id)
{
this.name = name;
this.id = id;
}
}
but this not work maybe.. actually I don't understand what actually my output is...
Not sure to really understand what you're asking for: if it's only about the meaning of the Debug.Log(robot); output, check for #Smartis answer as it answers it perfectly :)
Otherwise, I feel like you wanted to populate a List<Robot> with random picked names. In this case you need to use a loop: Start() method is only called once on start (as its name suggest). If you need to populate a list with random picked colors/names and then display how many of each colors/names are in the list you can do it as follow:
public class Test : MonoBehaviour
{
private void Start()
{
List<Robot> robotsList = new List<Robot>();
List<string> namesList = new List<string>();
namesList.Add("yellow");
namesList.Add("green");
namesList.Add("red");
PopulateRobotsList();
DisplayRobotsListContent();
}
private void PopulateRobotsList()
{
for(int id = 0; id < 100; id++)
{
string robotName = namesList[Random.Range(0, namesList.Count)];
robotsList.Add(new Robot(robotName, id));
//Debug.Log(robotsList[robotsList.Count - 1]);
}
}
private void DisplayRobotsListContent()
{
int[] robotsNamesCount = new int[namesList.Count];
for (int i = 0; i < robotsList.Count; i++)
{
robotsNamesCount[namesList.IndexOf(robotsList[i].name)] += 1;
}
for (int i = 0; i < namesList.Count; i++)
{
Debug.Log("Robot(s) named \"" + namesList[i] + "\" : " + robotsNamesCount[i]);
}
}
}
public class Robot
{
public string name;
public int id;
public Robot(string name, int id)
{
this.name = name;
this.id = id;
}
}
Please note I changed some variable names as I found it really hard to understand with the one you provided (ex: robotsList to store the potential colors/names of the robots is a weird choice of name :) ).
Hope this helps,
Your random pick works fine (even when your code is a little bit confusing). I guess your problem is, you don't understand the output of Debug.Log(robot);.
actually I don't understand what actually my output is... - OP
What does Debug.Log() print?
According to the Unity3D Documentation for this function will converted the given object to be to string representation for display. This means simply the return value of ToString() method on your Object will printed.
So let's have look at the Object.ToString() method and it's behavior in the MSDN Documentation.
Default implementations of the Object.ToString method return the fully qualified name of the object's type. - MSDN
So, your output in the Unity Log will be the Type Definition of your object.
Now, how to get useful information?
Just override the default ToString() method of your Robot class to something like this:
public class Robot
{
public string name;
public int id;
public Robot(string name, int id)
{
this.name = name;
this.id = id;
}
// Here start's the magic!
public override string ToString()
{
return string.Format("Robot -> Id:'{0}' Name:'{1}'", id, name);
}
}

can I initialize array instance variable outside class? What is the best OOP approach to below code?

I have to implement switchboard class which can have devices like Fan, AC, Bulb etc. My switch board class looks like below.
Which one is more object oriented?
1.
class SwitchBoard
{
public static int totalDevices=0;
public List<ElectricDevice> Devices { get; set; }
public SwitchBoard(int noOfFans, int noOfACs, int noOfBulbs)
{
Devices = new List<ElectricDevice>();
//int deviceCount = 0;
for (int i = 0; i < noOfACs + noOfBulbs + noOfFans; i++)
{
if (i < noOfFans)
{
Devices.Add(new Fan("Fan " + (i + 1),totalDevices));
}
else if (i >= noOfFans && i < noOfFans + noOfACs)
{
Devices.Add(new AC("AC " + (i - noOfFans + 1), totalDevices));
}
else
{
Devices.Add(new Bulb("Bulb " + (i - noOfFans - noOfACs + 1), totalDevices));
}
totalDevices++;
}
}
}
2.
class SwitchBoard
{
public static int totalDevices=0;
public List<ElectricDevice> Devices { get; set; }
public SwitchBoard(int noOfFans, int noOfACs, int noOfBulbs)
{
Devices = new List<ElectricDevice>();
CreateDevice(Devices, "Fan", noOfFans);
CreateDevice(Devices, "AC", noOfACs);
CreateDevice(Devices, "Bulb", noOfBulbs);
}
I am feeling like first one is best approach because in second method we are using method which intstantiate the class outside class by taking property outside the class and intializing outside it. Like taking out switch out of the swtichboard and connecting it to fan and placing it back into switch board.
I think it has something to do with encapsulation.
Pseudo code for CreateDevice
function CreateDevice(List<EelectricDevice> Devices, string type, int noOfObjects )
{
for(int i=Devices.Length; i<noOfDevices+Devices.Length;i++)
{
if(type=="Fan")
Device[i]=new Fan("Fan"+i);
else if(type=="AC")
Device[i]=new AC("AC"+i);
else if(type=="Bulb")
Device[i]=new Bulb("Bulb"+i);
}
}
I would refactor that loop into a generic method to which you send a number (which represent the number of devices, and pass it function which returns an Electrical device:
public delegate ElectricDevice Func<ElectricDevice>()
private addElectricalDevices(int number, Func<int, ElectricDevice> createDeviceFunc)
{
for(int i = 0; i < number; i++)
{
Devices.Add(createDeviceFunc(i));
}
}
Example usage:
addElectricalDevices(10, (i) => new Fan("Fan " + (i + 1)));
Sorry, it's been long since i wrote C# code so this might not be perfect.
Designing of a system is something that is difficult to suggest as there are many things that needs to be considered.
But keeping it minimum and sticking to your question, there are a few things that needs to be considered -
Suggest to have an interface like ISwitchable, to be implemented by ElectricDevice which are switchable. This is important conceptually, as not all ElectricDevices are meant to be switchable -
public interface ISwitchable
{
}
Now you can implement this in you device something like this -
public class Fan : ElectricDevice, ISwitchable
{
//Implementation of fan
}
For the total number of devices, it should be implemented as a read only property, which is calculated as a sum of all the devices, other there is a possibility of this value get tampered. There is no need to calculate this value with each iteration.
At the end this is how you SwitchBoard class might look like -
public class SwitchBoard
{
public List<ISwitchable> switchableDevices { get; private set; }
public int TotalSwichableDevices
{
get { return numberOfFans + numberOfACs + numberOfBulbs; }
}
private readonly int numberOfFans;
private readonly int numberOfACs;
private readonly int numberOfBulbs;
public SwitchBoard(int noOfFans, int noOfACs, int noOfBulbs)
{
this.numberOfFans = noOfFans;
this.numberOfACs = noOfACs;
this.numberOfBulbs = noOfBulbs;
switchableDevices = new List<ISwitchable>();
switchableDevices.AddRange(this.AddFans());
//TODO: Add other devices
}
private IEnumerable<ISwitchable> AddFans()
{
List<ISwitchable> fans = new List<ISwitchable>();
for (int i = 0; i < numberOfFans; i++)
{
fans.Add(new Fan());
}
return fans;
}
}

Use a static or a non static class

I got a class that I made static, but is it a bad option? Should it be a non static class?
I want to set two values in my class.
Is there any chance when you give properties values that there will be some kind of conflict when setting them and when getting them? If another user have the same target.
I got a page that calling this class.
One user hits the page and this happens.
Set the properties for the calculation
Run the void to calculate two properties
"Maybe some other functions runs and take some time"
Get the value of the two properties
But what if another user hits the page and sets other values and make either the first user's value incorrect. I guess that's possible?
Some other options I thought of is to either
Send all properties into the void as arguments and return a new class with my two values I need. (Not store them as a static property that could be changed by another user before it got used).
Create a new class with the properties (perhaps called BreakTime). Send that into the void as one argument. Return it, calculated.
Or you tell me what the best option is! :)
Here how it looks:
public static class BreakTimeCalculator
{
public static int BreakFromSec { get; private set; }
public static int BreakUntilSec { get; private set; }
public static int CustomBreakSec { get; set; }
public static int FromSec { get; set; }
public static int UntilSec { get; set; }
public static int Equlizer { get; set; }
public static void CalculateBreakFromAndBreakeUntil()
{
var taskLength = UntilSec - FromSec;
var middleOfTask = FromSec + (taskLength / 2);
var secondsToMoveLeft = middleOfTask % 300;
var amountEqualizers = CustomBreakSec / Equlizer;
var fiftyFifty = amountEqualizers % 2 == 0;
var leftSideEqualizers = fiftyFifty ? amountEqualizers / 2 : (amountEqualizers / 2) + 1;
BreakFromSec = middleOfTask - secondsToMoveLeft - (leftSideEqualizers * Equlizer);
BreakUntilSec = BreakFromSec + CustomBreakSec;
}
}
Never create static state unless you really, really have to as you'll set yourself up for a fall if you do. You make testing harder and you make the likelihood of a thread conflict (as you describe) happening much higher.
If you must set state in a class and then invoke methods, rather than just passing the values as parameters to the method, make it a non-static class. Also, you should preferably pass the values in via the constructor, rather than using properties.
Having said that, my approach to your problem would be to create a POCO to hold the result data and have a static method to do the calculation. Using C# 6 syntax, this would look like:
public class BreakTimeResult
{
public BreakTimeResult(int breakFromSec, int breakUntilSec)
{
BreakFromSec = breakFromSec;
BreakUntilSec = breakUntilSec;
}
public int BreakFromSec { get; }
public int BreakUntilSec { get; }
}
public static class BreakTimeCalculator
{
public static BreakTimeResult CalculateBreakFromAndBreakeUntil(int customBreakSec,
int fromSec,
int untilSec,
int equlizer)
{
var taskLength = untilSec - fromSec;
var middleOfTask = fromSec + (taskLength / 2);
var secondsToMoveLeft = middleOfTask % 300;
var amountEqualizers = customBreakSec / equlizer;
var fiftyFifty = amountEqualizers % 2 == 0;
var leftSideEqualizers = fiftyFifty
? amountEqualizers / 2
: (amountEqualizers / 2) + 1;
var breakFromSec = middleOfTask - secondsToMoveLeft - (leftSideEqualizers * equlizer);
var breakUntilSec = breakFromSec + customBreakSec;
return new BreakTimeResult(breakFromSec, breakUntilSec);
}
}

Variable not returning actual values

I want correctly return some variables (arrays)
kazkas.Ads[n]; (n = how many ads are)
kazkas.Ads[n].id;
kazkas.Ads[n].Days[m].Stats.Clicks; // every day have his own clicks
kazkas.Ads[n].Days[m].Stats.Impresons; // every day have his own impresions
from this method and use these variables in other class.
public static void GetAdsStats(string Ticket, DateTime start, DateTime end, int CamId)
{
var client = new CampaignStatsServiceClient();
var id = new CampaignIdFilter();
id.CampaignId = CamId;
var statsdata = new GetAdStatsData();
var kazkas = new Campaign();
kazkas = client.GetAdStats(Ticket, new GetAdStatsData
{
IdFilter = id,
StartDate = start,
EndDate = end
});
long AllClicks = 0;
long AllImpresions = 0;
int reklamos = kazkas.Ads.Length;
long[] statistikaClikai = new long[reklamos];
long[] statistikaImpresions = new long[reklamos];
for (int i = 0; i < reklamos; i++)
{
int dienos = kazkas.Ads[i].Days.Length;
for (int lop = 0; lop < dienos; lop++)
{
AllClicks = AllClicks + kazkas.Ads[i].Days[lop].Stats.Clicks;
AllImpresions = AllImpresions + kazkas.Ads[i].Days[lop].Stats.Impressions;
}
statistikaClikai[i] = AllClicks;
statistikaImpresions[i] = AllImpresions;
}
}
I know that void type can't return anything, but this how I know that my method works ( from debugging). Like you see I was trying do that with for loop. Here i have 9 Ads and every ad have one day.
Like I says I want return every Ads id[in array], and every days.stats.impresions and days.stats.click
how can I do that ? Ore how return more variables/arrays from method to other class, I am using webservises, so i cant use database ore something like that.
As can be seen by the downvotes of the question, you need to design the return value and then code against it.
Your query almost does it (now):
kazkas.Ads[n]; (n = how many ads are)
kazkas.Ads[n].id;
kazkas.Ads[n].Days[m].Stats.Clicks; // every day have his own clicks
kazkas.Ads[n].Days[m].Stats.Impressions; // every day have his own impressions
Your existing code show this should be expanded to include:
kazkas.Ads[n].Total.Clicks;
kazkas.Ads[n].Total.Impressions;
So now you're ready to design. First you want a Stat Class that just contains CLicks and Impressions:
public class Stat
{
public long Impressions { get; set; }
public long Clicks { get; set; }
}
An optimisation here may be to use a struct, but I won't go into that.
As you currently have defined it each Day has just a Stats property:
public class DayStat
{
public Stat Stats { get; set; }
}
Now finally we can define the top level AdStat:
public class AdStat
{
public int id { get; set; }
public DayStat Day[];
public Stat Total { get; set; }
}
Etc... There's further issues here, such as ensuring arrays are created and Stat instances are never null (which is why making some of these classes structs is an option). But I'm really a VB programmer so I'll stop here before I get caught typing crap into the SO IDE :-)
Create a class or struct with members you need
public class Stat
{
public int Id { get; set; }
public long Clicks { get; set; }
...
}
Change the signature of your method from void GetAdsStats to IEnumberable<Stat> GetAdsStats and either return a collection of stats or use yield keyword to return the stat object.
Also if you do not want your method to return anything (return type void) do not use a name starting with Get.
Example:
public static IEnumerable<Stat> GetAdsStats(...)
{
...
var statList = new List<Stat>();
for (int i = 0; i < reklamos; i++)
{
var stat = new Stat();
statList.Add(stat);
int dienos = kazkas.Ads[i].Days.Length;
for (int lop = 0; lop < dienos; lop++)
{
AllClicks = AllClicks + kazkas.Ads[i].Days[lop].Stats.Clicks;
AllImpresions = AllImpresions + kazkas.Ads[i].Days[lop].Stats.Impressions;
}
stat.Clicks = AllClicks;
stat.Impression = AllImpresions;
}
return statList;
}
Change your void to the type you want to return, say Campaign, and return the appropriate variable. The variables you define in your method, only live in your method and are not accessible from another method or class.

How to create a simplified assignment or default property for a class in C#

This is minor, I know, but let's say that I have a class Character and a class Ability (mostly because that's what I'm working on). Class Character has six abilities (so typical D&D...). basically:
public class Character
{
public Character()
{
this.Str = new Ability("Strength", "Str");
this.Dex = new Ability("Dexterity", "Dex");
this.Con = new Ability("Constitution", "Con");
this.Int = new Ability("Intelligence", "Int");
this.Wis = new Ability("Wisdom", "Wis");
this.Cha = new Ability("Charisma", "Cha");
}
#region Abilities
public Ability Str { get; set; }
public Ability Dex { get; set; }
public Ability Con { get; set; }
public Ability Int { get; set; }
public Ability Wis { get; set; }
public Ability Cha { get; set; }
#endregion
}
and
public class Ability
{
public Ability()
{
Score = 10;
}
public Ability(string Name, string Abbr)
: this()
{
this.Name = Name;
this.Abbr = Abbr;
}
public string Name { get; set; }
public string Abbr { get; set; }
public int Score { get; set; }
public int Mod
{
get
{
return (Score - 10) / 2;
}
}
}
When actually using these ability properties in future code, I'd like to be able to default to just the score, like so:
//Conan hits someone
int damage = RollDice("2d6") + Conan.Str;
//evil sorcerer attack drains strength
Conan.Str = 0;
rather than:
//Conan hits someone
int damage = RollDie("2d6") + Conan.Str.Score;
//evil sorcerer attack drains strength
Conan.Str.Score = 0;
Now, the first case can be taken care of with an implicit conversion:
public static implicit operator int(Ability a)
{
return a.Score;
}
Can anybody help me with the reverse? Implicit conversion like this:
public static implicit operator Ability(int a)
{
return new Ability(){ Score = a };
}
will replace the entire attribute rather than just the score of the attribute—not the desired result...
The best you can do is increment the score by adding these methods to Ability.
public static Ability operator + (Ability lhs, int score)
{
lhs.Score += score;
return lhs;
}
public static Ability operator - (Ability lhs, int score)
{
lhs.Score -= score;
return lhs;
}
public static implicit operator int(Ability rhs)
{
return rhs.Score;
}
and using them like:
static void Main(string[] args)
{
Character evil = new Character(); //Str.Sccore=10
evil.Str += 10; //cast spell for Str.Sccore=20
evil.Str -= evil.Str; //death with Str.Sccore=0
}
First, keep your implicit conversion:
public static implicit operator Ability(int a)
{
return new Ability(){ Score = a };
}
Then in your character class: Add a private Ability attribute for str, and change the getter and the setter of the Str property as follows:
private Ability str;
public Ability Str
{
get
{
return this.str;
}
set
{
if (value.Name == "")
{
this.str.Score = value.Score;
}
else
{
this.str = value;
}
}
}
There you go :)
You could also use:
if(string.IsNullOrWhiteSpace(value.Name))
instead of
if (value.Name == "")
If you are compiling to .NET 4.0 version
EDIT: I gave you a solution that does exactly what you wanted to, but What ja72 wrote is also a good suggestion with operators + and -; you can add his solution to mine (or mine to him, whatever), it will work just fine. You will then be able to write:
Character Jax = new Character(); // Str.Score = 10
Character Conan = new Character(); // Str.Score = 10
Jax.Str = 2000; // Str.Score = 2000;
Conan.Str += 150; // Str.Score = 160
Another option is to replace the properties with delegates like this
public class Character
{
public Character()
{
...
}
#region Abilities
...
#endregion
public Func<int> Strength
{
get { return () => Str.Score; }
set { Str.Score = value(); }
}
}
and use it like this
Character evil = new Character(); //Str.Sccore=10
// fist spell hits
evil.Strength = () => 5; //set Str.Score=5
// second spell hits
evil.Strength = () => 0; //set Str.Score=5
if (evil.Strength() == 0)
{
// dead
}
Perhaps you could make Ability abstract and then derive new classes from Ability for each of the sub-classes: Strength, ...
The constructor for the Strength class would look something like this:
public Strength () : base ("Strength", "Str") { ...}
Now the ability properties off a Character would be strongly typed and the implicit conversions could turn a value like 5 into a Strength object with a value of 5. This would also prevent you from accidentally storing a Dexterity in a Strength property, for example.
[Assuming the name and abbreviations are in fact fixed for all objects of that type.]

Categories