Correctly accessing parameters from a " : Base" constructor - c#
Situation
I'm making a small text based game using some OOP practices I learnt this academic year, the reason I'm doing this is to mostly improve the OOP that I currently know and hopefully improve some of my practices with assistance from experienced users.
So, in layman terms, I currently have an "Ork" class that's extending "Enemy" and "Enemy" is extending "Entity"
public class Ork : Enemy
public class Enemy : Entity
I have the "Enemy" class because I intend to make many unique enemy object types, not just "Ork", with this current setup I could make "Elf" or "Human" the same way. (and it's much easier to add new types in the future) Enemy has it's own constructor.
public Enemy(string[] Droplist, int Defaultgold, string Weaknesses, string Resistances, string[] Taunts, string Aggro, string Critchance, string Threshold, string Name, string Type,
string Spawnzone, string _Class, int Defaultlevel, int Maxlevel, string trait, int str, int agi, int dex, int hel, int man)
{
//make a new entity instance.
entity = new Entity();
//Set all the local variables to the passed in parameters.
setEntity(Name, Type, Spawnzone, _Class, Defaultlevel, Maxlevel, trait, str, agi, dex, hel, man);
droplist = Droplist;
defaultgold = Defaultgold;
weaknesses = Weaknesses;
resistances = Resistances;
taunts = Taunts;
aggro = Aggro;
critchance = Critchance;
threshold = Threshold;
}
As you can see, I set the incoming parameter to the local variable, and I use setEntity which does some of this work for me. I also have an "Entity" class, and the reason for this is, not everything that has "Stats" is an enemy, therefore I have "Entity" as the middleman.
Problem
The problem is at the end of this line of classes, the Ork Class.
In other programs, for instance, my Hillracing program, my constructor for a similar class would look like this:
public JuniorMember(string stringfirstname, string stringlastname, string stringmiddlename, string stringtitle, string strst, string strtwn, string strpc, string strEmail, int intMobile, int intHome,
string shrnumber, string memtype, string username, string password, int noracesrun, float perraceswon, string mempic, string memclub, string gender, int memexp, int yearofbirth, int monthofbirth, int dayofbirth, string nextofkin, string docName, string docTel, string healthIssues, string parentalConsent)
: base(stringfirstname, stringlastname, stringmiddlename, stringtitle, strst, strtwn, strpc, strEmail, intMobile, intHome, shrnumber, memtype, username, password, noracesrun, perraceswon, mempic, memclub,
gender, memexp, yearofbirth, monthofbirth, dayofbirth)
{
So, the problem is, simply put, In this program I'm looking at a similar amount of parameters, and for me, personally, looking at these parameters I don't feel as if I'm doing this correctly.
The example I gave from Hillracing works flawlessly, but I'm just wondering if this is the best way to do this, as the parameter list looks messy and it feels as if I'm creating things that have already been previously created. What I mean by this is, 90% of the information I need to create an Ork object comes from elsewhere.
Edit
Due to comments made, I removed the new Entity I had made in my enemy class, I now have the following Enemy class:
public class Enemy : Entity
{
private string[] droplist;
private int defaultgold;
private string weaknesses;
private string resistances;
private string[] taunts;
private string aggro;
private string critchance;
private string threshold;
public string[] Droplist { get { return droplist; } set { droplist = value; } }
public int Defaultgold { get { return defaultgold; } set { defaultgold = value; } }
public string Weaknesses { get { return weaknesses; } set { weaknesses = value; } }
public string Resistances { get { return resistances; } set { resistances = value; } }
public string[] Taunts { get { return taunts; } set { taunts = value; } }
public string Aggro { get { return aggro; } set { aggro = value; } }
public string Critchance { get { return critchance; } set { critchance = value; } }
public string Threshold { get { return threshold; } set { threshold = value; } }
public void setEntity(string EnName, string EnType, string EnSpawnzone, string En_Class, int EnDefaultlevel, int EnMaxlevel, string Entrait, int Enstr, int Enagi, int Endex, int Enhel, int Enman)
{
setStats(Enstr, Enagi, Endex, Enhel, Enman);
Name = EnName;
Type = EnType;
Spawnzone = EnSpawnzone;
_Class = En_Class;
Defaultlevel = EnDefaultlevel;
Maxlevel = EnMaxlevel;
trait = Entrait;
}
public Enemy(string[] Droplist, int Defaultgold, string Weaknesses, string Resistances, string[] Taunts, string Aggro, string Critchance, string Threshold)
:base(Name,Type,Spawnzone,_Class,Defaultlevel,Maxlevel,trait,str,agi,dex,hel,man)
{
//Set all the local variables to the passed in parameters.
setEntity(Name, Type, Spawnzone, _Class, Defaultlevel, Maxlevel, trait, str, agi, dex, hel, man);
droplist = Droplist;
defaultgold = Defaultgold;
weaknesses = Weaknesses;
resistances = Resistances;
taunts = Taunts;
aggro = Aggro;
critchance = Critchance;
threshold = Threshold;
}
My issue here is, I don't know how to get the information from Entity at this point, I can't access the Name,Type,Spawnzone,etc,etc variables because they expect an object reference.
Note: I see that you just edited to clarify that your Enemy class extends Entity. Then I'm not understanding why you are instantiating an Entity class inside the Enemy constructor. What is the logical relationship between Entity and Enemy? Is Enemy a type of Entity? Or, does Enemy have an Entity?
Perhaps you can consider passing in the Entity instance to the Enemy constructor to avoid having to pass in all the individual components of the Entity class to the Enemy constructor. Something like this:
public class Entity {
// other code
public Entity(string Type, string Spawnzone, string _Class, int Defaultlevel, int Maxlevel, string trait, int str, int agi, int dex, int hel, int man) {
// move setEntity code here.
}
// other code
}
public class Enemy {
// other code
public Enemy(string[] Droplist, int Defaultgold, string Weaknesses, string Resistances, string[] Taunts, string Aggro, string Critchance, string Threshold, string Name, Entity entity) {
this.entity = entity;
droplist = Droplist;
defaultgold = Defaultgold;
weaknesses = Weaknesses;
resistances = Resistances;
taunts = Taunts;
aggro = Aggro;
critchance = Critchance;
threshold = Threshold;
}
// other code
}
Entity should be a base class that Enemy extends (with the additional stats that not all entities have). From Enemy's constructor you should call the parent Entity constructor. This makes sense because Enemy "is a(n)" Entity.
Whereas, currently, your setup is such that Enemy "has a(n)" Entity, which doesn't make sense.
Edit
You have this already:
public class Ork : Enemy
I'm saying, you also need to have this:
public class Enemy : Entity
And C# I think class base class constructors automatically, so you don't have to do anything else. Just do everything common to all Entitys in the Entity constructor, Enemys in Enemy, and so forth.
I assume that your Enemy class is containing an instance of Entity. Which is a wrong practice in your case. And if your Enemy class is extended by Entity then you can use its constructor to set generic values to parent class. Just like you have done it in HillRacing program.
(Make sure your Enemy class does not have a member of Entity Type. if it is base of Enemy )
public class Entity
{
public string Type;
public string Spawnzone;
public string _Class;
public string Defaultlevel;
public string Maxlevel;
public string Trait;
public string str;
public string agi;
public string dex;
public string hel;
public string man;
public Entity(string Type, string Spawnzone, string _Class, int Defaultlevel, int Maxlevel, string trait, int str, int agi, int dex, int hel, int man)
{
this.Type = Type;
this.Spawnzone = Spawnzone;
this._Class = _Class;
this.Defaultlevel = Defaultlevel;
this.Maxlevel = Maxlevel;
this.Trait = trait;
this.str = str;
this.agi = agi;
this.dex = dex;
this.hel = hel;
this.man = man;
}
}
public class Enemy
{
public string[] droplist;;
public int defaultgold;
public string weaknesses;
public string resistances;
public string[] taunts;
public string aggro;
public string critchance;
public string threshold;
public Enemy(string[] Droplist, int Defaultgold, string Weaknesses, string Resistances, string[] Taunts, string Aggro, string Critchance, string Threshold, string Name, string Type, string Spawnzone, string _Class, int Defaultlevel, int Maxlevel, string trait, int str, int agi, int dex, int hel, int man )
: base(Type, Spawnzone, _Class, Defaultlevel, Maxlevel, trait, str, agi, dex, hel, man)
{
droplist = Droplist;
defaultgold = Defaultgold;
weaknesses = Weaknesses;
resistances = Resistances;
taunts = Taunts;
aggro = Aggro;
critchance = Critchance;
threshold = Threshold;
}
}
Related
JavaScriptSerializer does not serialize a second level
I am trying to use JavaScriptSerializer and I have got good results when I want to serialize a list of objects of a class like public class employee { public string id; //unique id of the employee public string displayName; public int displayFlag; public employee(string i, string dN, int dF) { id = i; displayName = dN; displayFlag = dF; } } public class data2 { public List<employee> detail; } When I do the following var json = new JavaScriptSerializer(); string jsonData = json.Serialize(data2); (and data2 is an object of class data2) However when I try to do the same for something a little more complicated such as public class Ccanister { string identifier; public Ccanister(string c) { identifier = c; } } public class medicine { public string id; //unique id public string displayName; //and here an array of canisters public List<Ccanister> canister; } public class dataMedicine { public List<medicine> detail; //Change this } and I do this string jsonMedi = json.Serialize(dataM); I got wrong results. dataM has correct results (I debugged it) but when jsonMedi gets its results, the canister list 'canister' is always empty. (It was not empty in dataM) I wonder what I am doing wrong here
get a value from data (not list or dictionary)
Sorry im newb and I don't know how to ask my question properly in the title. I have a database: class PlayerData { public ulong id; public string name; public int kills; public int deaths; } and I want to return the value corresponding to the requested key object getStats(ulong uid, string stat) { var player = BasePlayer.FindByID(uid); PlayerData data = PlayerData.Find(player); object value = data.TryGetValue(stat); // I know this ain't right return value; } example: int kills = getStats(123456, kills); //will ask for the value of "kills" in the data. Return data.kills stat could be anything in data (id, name, kills, deaths) thanks alot!
You could take Sun Maung Oo's suggestion of using a switch statement: object TryGetValue(int playerId, string name) { var player = GetPlayer(playerId); switch (name) { case "name": return name; case "kills": return kills; // Other properties // ... default: return null; } } Or you could flatten the data: public class Statistic { public int PlayerId { get; set; } public string Name { get; set; } public object Value { get; set; } } Then finding the value is a matter of finding the statistic with the given player id and name.
I suppose what you are trying to do here is to get the object value base on the object Name? If that is the case, I think you could use reflection to achieve that. You could reference this answer: Get property value from string using reflection in C# Sample Code: class PlayerData { public ulong id; public string name; public int kills; public int deaths; } object getStats(ulong uid, string stat) { var player = BasePlayer.FindByID(uid); PlayerData data = PlayerData.Find(player); object value = data.GetType().GetProperty(stat).GetValue(data, null); return value; }
Change variables based on time elapsed
I'm trying to create a program within which the user interacts with a virtual pet. This pet has attributes such as hunger, which is just stored as an integer between 1-10. Is there a way to decrease the value of said variable based on how much time has passed (since the pet was last fed, let's say)? Hopefully i can use it to create a function like this: static void hungerDecrease(CPet pet) { bool needsFeeding = false; // some method of checking if say 4 hours has passed and if so set needsFeeding to be true if (needsFeeding == true) { pet.Hunger -= 1; } } The class CPet looks like this: public class CPet { public string Name; public string Gender; // Attributes belonging to pets, with values being defined upon creation. public int Hunger = 5; public int Boredom = 5; public int Happiness = 5; public int Intelligence = 1; public CPet(string name, string gender) { Name = name; Gender = gender; } }
public class CPet { public string Name; public DateTime LastFed; ... } static void hungerDecrease(CPet pet) { if (DateTime.Now > pet.LastFed.AddHours(4)) { pet.Hunger -= 1; pet.LastFed = DateTime.Now; } }
Want to create multiple objects of a class at runtime
I am a complete fresher I have been told to create a class for Candidate .. after creating the database for the module. What I have created is public class Class1 { public class JobHistory { public string CompName, Tech, Profile; public string StartDate; public string EndtDate; public int CurrentAnnualSalary; public void AddNew(string CompName, string Tech, string Profile, string StartDate, string EndtDate, int CurrentAnnualSalary) { this.CompName = CompName; this.Tech = Tech; this.Profile = Profile; this.StartDate = StartDate; this.EndtDate = EndtDate; this.CurrentAnnualSalary = CurrentAnnualSalary; } } public class PersonalInformation { public string FirstName, LastName, DateOfBirth, PhoneNo1, PhoneNo2; public string EmailId; public int TotalExperienceInMonths; public void AddNew(string FirstName, string LastName, string DateOfBirth, string PhoneNo1, string PhoneNo2, int TotalExperienceInMonths, string EmailId) { this.FirstName = FirstName; this.LastName = LastName; this.DateOfBirth = DateOfBirth; this.PhoneNo1 = PhoneNo1; this.PhoneNo2 = PhoneNo2; this.EmailId = EmailId; this.TotalExperienceInMonths = TotalExperienceInMonths; } } public class Skills { int SkillId; string Skill; } public class Candidate { int CandidateId; JobHistory jh1 = new JobHistory(); PersonalInformation pi = new PersonalInformation(); public void AddNew(int CandidateId,JobHistory jh2,PersonalInformation pi2) { this.CandidateId = CandidateId; this.jh1.AddNew(jh2.CompName, jh2.Tech, jh2.Profile, jh2.StartDate, jh2.EndtDate, jh2.CurrentAnnualSalary); this.pi.AddNew(pi2.FirstName, pi2.LastName, pi2.DateOfBirth, pi2.PhoneNo1, pi2.PhoneNo2, pi2.TotalExperienceInMonths, pi2.EmailId); } public void UpdateExisting(); public void Delete(); } } here I wanted to another class of Skills. But from the frond end the candidate will have multiple skills and he will update them. So for that I wanted the objects of class skills to be created at the runtime so should I be using the List<>? How to go ahead? Am I correct till now?
As #Jon skeet mentioned you need to use the Constructor and you need to remove the class1 nested class rarely required. Start with writing constructor for your classes in place of AddNew method like below public class JobHistory { public string CompName, Tech, Profile; public string StartDate; public string EndtDate; public int CurrentAnnualSalary; public JobHistory(string CompName, string Tech, string Profile, string StartDate, string EndtDate, int CurrentAnnualSalary) { this.CompName = CompName; this.Tech = Tech; this.Profile = Profile; this.StartDate = StartDate; this.EndtDate = EndtDate; this.CurrentAnnualSalary = CurrentAnnualSalary; } //If required then you can also need write out the empty constructor public JobHistory(){} } You can also change your class1 into the namespace so your classes can stay in same namespace. More info on namespace namespace StudeProfileProject And one more thing, If you are declaring the properties as public then use the getters and setters at the time of declaration so your final class will be look like, public class JobHistory { public string CompName{get;set} public string Tech {get;set;} public string Profile{get;set;} //More properties .... public JobHistory() {} public JobHistory(string CompName, string Tech, string Profile, string StartDate, string EndtDate, int CurrentAnnualSalary) { this.CompName = CompName; this.Tech = Tech; this.Profile = Profile; this.StartDate = StartDate; this.EndtDate = EndtDate; this.CurrentAnnualSalary = CurrentAnnualSalary; } } If you want multiple skills for each Candidate then List will be good option and you can declare it in the your Candidate class public class Candidate { int CandidateId; JobHistory jh1 = new JobHistory(); PersonalInformation pi = new PersonalInformation(); List<Skill> CandidateSkills = new List<Skills>(); public Candidate(int CandidateId,JobHistory jh2,PersonalInformation pi2) { this.CandidateId = CandidateId; this.jh1= new JobHistory (jh2.CompName, jh2.Tech, jh2.Profile, jh2.StartDate, jh2.EndtDate, jh2.CurrentAnnualSalary); this.pi = new PersonalInformation (pi2.FirstName, pi2.LastName, pi2.DateOfBirth, pi2.PhoneNo1, pi2.PhoneNo2, pi2.TotalExperienceInMonths, pi2.EmailId); } public void UpdateExisting(); public void Delete(); } And you will be able to use all the Collection methods for your need. Here is more info on it.
First, you could replace the AddNew-Methods with Constructors. For your Candidate class it could look like this: public Candidate(int CandidateId,JobHistory jh2,PersonalInformation pi2) Using a List<Skill> is a good idea. You can then use the Add-Method to add a skill.
Possible class function in C#
I have a class created: public class character { public string Name, Owner; public int Str, Con, Dex, Int, Wis, Cha, AC, Speed, maxHP, currHP, AP, SV, Surges; } As you can see, it's a very simple class at the moment. My question is, is there a way to create another class inside this so when I call my function I can have a math equation returned? Example: character c = new character(); c.Name = "Goofy"; c.Owner = "Me"; c.Str = 15; MessageBox.Show(c.Str.Mod); The output to the window would be "7" (Mod is: Math.Floor(Str / 2);) I have been trying to search both SO and Google for some time and have yet to figure this out. I may be searching for the wrong phrases or this might not even be possible. Thanks
only way that I can quickly think is Extension Methods class Program { static void Main(string[] args) { character c = new character(); c.Name = "Goofy"; c.Owner = "Me"; c.Str = 15; Console.WriteLine(c.Str.Mod()); Console.Read(); } } public class character { public string Name, Owner; public int Str, Con, Dex, Int, Wis, Cha, AC, Speed, maxHP, currHP, AP, SV, Surges; } public static class Ext { public static int Mod(this int value) { return (int)Math.Floor(value / 2.0); } }
public class Character // C should be uppercase here. { public string Name, Owner; public int Str, Con, Dex, Int, Wis, Cha, AC, Speed, maxHP, currHP, AP, SV, Surges; public double ModMe() { return Math.Floor(this.Str / 2); // Math.Floor returns double } } character c = new character(); c.Name = "Goofy"; c.Owner = "Me"; c.Str = 15; MessageBox.Show(c.ModMe());
or: public class character { public string Name, Owner; public int Str, Con, Dex, Int, Wis, Cha, AC, Speed, maxHP, currHP, AP, SV, Surges; public int StrMod{ get{ return (int)Math.Floor(Str / 2); } } } used with: character c = new character(); c.Name = "Goofy"; c.Owner = "Me"; c.Str = 15; MessageBox.Show(c.StrMod);
Yes, you can create a method called Mod that will do your math for you. It'd look something like this: public class character { public string Name, Owner; public int Str, Con, Dex, Int, Wis, Cha, AC, Speed, maxHP, currHP, AP, SV, Surges; public double Mod(int stat) { return Math.Floor(stat/2); } }
Create an interface. Use properties. Use descriptive variable names: public interface ICharacter { public string Name { get; } public int Strength { get; } } Then implement it: public class Character : ICharacter { public string Name { get; private set; } public int Strength { get; private set; } public Character(string name, int strength) { this.Name = name; this.Strength = strength; } } Now for your question, you should let one class do one thing. So now you can create and initialize a calculator for a character's damage modifier (or whatever "Mod" means): public class DamageModifierCalculator { public int Calculate(ICharacter character) { return (int)Math.Floor(character.Strength / 2); } } Now initialize and call it: var character = new Character("Goofy", 15); var calculator = new DamageModifierCalculator(); int mod = calculator.Calculate(character); It's extensible, it's testable and its concerns are separated. You will want to create an interface for the calculator too, as you'll need more of them, preferably one for each kind of calculation. Or you can just stick it in your Character class, but then it's got nothing to do with OO anymore.
Rather than using Int fields for your stats (at least for your example), make a Stat class, like so: public class character { public string Name, Owner; public int AC, Speed, maxHP, currHP, AP, SV, Surges; public Stat Str { get; set; } public Stat Con { get; set; } public Stat Dex { get; set; } public Stat Int { get; set; } public Stat Wis { get; set; } public Stat Cha { get; set; } public class Stat { public Stat(int stat) { Value = stat; } public int Value { get; set; } public int Mod { get { /*Calcuate Mod from Value.*/; } } } } And call it like this: character c = new character(); c.Name = "Goofy"; c.Owner = "Me"; c.Str = new Stat(7); MessageBox.Show(c.Str.Value); //The Value MessageBox.Show(c.Str.Mod); //The Mod of Strength
For this operation, you can just do : int x = (int)15 / 2; Also, you can create nested class, that is to say, a class inside a class. For example, you would have inside your class something like : public class MathOperator { public int Mod(int x) { return (int)x/2; } } And then, just create an instance of this nested class in your class, and use it on c.Str
If Mod is a operation that could apply to any integer, you could define it as an extension method. static class ExtendInt { static public int Mod(this int stat) { return stat / 2; } } class UseExtendedInt { void UseIt() { int a = 1; int b = a.Mod(); } } If you put ExtendInt inside a unique namespace, you can use that namespace only in the files where you want this to work, but otherwise this will be an available function for all integers in that namespace. If this needs different operations depending on the variable name, you'll have to somehow incorporate reflection or define an enum that identifies the calculation type to pass into Mod. In most cases, if the calculation types are different, you're better off defining properties like strMod, conMod, etc...
To use that exact syntax, you would need Str to be a different type. One that can be converted from an int and have a property named Mod: public class character { // A type that is convertible from int and has a Mod property public class Modder { //private variable to hold the integer value private int _value; // private constructor that is used by the converter private Modder(int value){ _value = value; } // implicit converter to handle the conversion from int public static implicit operator Modder(int value) { return new Modder(value); } // Property Mod that does the calculation public int Mod { get { return _value / 2; } } } public string Name, Owner; public int Con, Dex, Int, Wis, Cha, AC, Speed, maxHP, currHP, AP, SV, Surges; public Modder Str; } I put that class insde the character class, but it doesn't have to be.
public class character { public string Name, Owner; public int Str, Con, Dex, Int, Wis, Cha, AC, Speed, maxHP, currHP, AP, SV, Surges; public int MathFunction(int input) { return (int)(input/2); } } now you can use MessageBox.Show(c.MathFunction(c.Str));