This is the first class:
public class TextBoxInt : TextBox
{
public int min;
public int max;
public Value<int> value;
public virtual void Update(object sender, EventArgs e)
{
int newValue;
if (int.TryParse(Text, out newValue))
{
if (newValue < min || newValue > max)
{
//do thing A
}
value.Set(newValue);
Text = value.Get().ToString();
}
else
{
Text = value.Get().ToString();
Focus();
}
}
public TextBoxInt(Value<int> value, int min, int max)
{
this.value = value;
this.min = min;
this.max = max;
Text = value.Get().ToString();
LostFocus += new EventHandler(update);
}
}
This is the second class:
public class TextBoxFloat : TextBox
{
public float min;
public float max;
public Value<float> value;
public virtual void Update(object sender, EventArgs e)
{
float newValue;
if (float.TryParse(Text, out newValue))
{
if (newValue < min || newValue > max)
{
//do thing A
}
value.Set(newValue);
Text = value.Get().ToString();
}
else
{
Text = value.Get().ToString();
Focus();
}
}
public TextBoxFloat(Value<float> value, float min, float max)
{
this.value = value;
this.min = min;
this.max = max;
Text = value.Get().ToString();
LostFocus += new EventHandler(update);
}
}
Also, this is the Value class :
public class Value<T>
{
private T value;
private List<IValueListener<T>> listeners = new List<IValueListener<T>>();
public Value(T value)
{
this.value = value;
}
public T Get()
{
return value;
}
public void Set(T value)
{
this.value = value;
foreach (IValueListener<T> listener in listeners)
{
listener.ValueUpdated(this);
}
}
public void AddListener(IValueListener<T> listener)
{
listeners.Add(listener);
}
public void RemoveListener(IValueListener<T> listener)
{
listeners.Remove(listener);
}
}
As you can see, the first two classes are basically the same class. The only difference is the type. First one is int, the other one float. It seems that I would make for nicer code if I could combine those two into a single class.
I can set min and max to be floats and just cast them to int when needed if it's an int class. I'd just make sure I pass "whole" floats when the type is int.
Is there any way I can do it without duplicating Update() method (If int do codeForInt, else if float do sameCodeButForFloat)?
Also, even if I do duplicate the code, I run into a problem with value.Set(newValue); - in one case newValue would be int, in other it would be float, and I can't cast either to T.
Also, is there a way to limit the generic type? To specify it can only be int or a float?
Should I just leave them as two classes, or is there a way to unify them?
Instead of making separate classes, you could make a generic class.
public class BoundedTextBox<T> : TextBox where T : IComparable<T> ...
Declaring that T implements IComparable<T> will allow you to check if T is in bounds during your set operation.
if (newValue.CompareTo(min) <= 0 || newValue.CompareTo(max) >= 0)
{
// do thing A
}
What about having an abstract TextBox<T> class inheriting from the TextBox class, where TextBox<T> has a new abstract string GetValue() method? You'll have TextBoxFloat class implementing GetValue() which will do the float specific logic and similarly will the TextBoxInt class. Your TextBox<T> would be something like
public abstract class TextBox<T> : TextBox
{
public T min;
public T max;
public Value<T> value;
public virtual void Update(object sender, EventArgs e)
{
Text = GetValue();
Focus();
}
public TextBoxFloat(Value<T> value, T min, T max)
{
this.value = value;
this.min = min;
this.max = max;
Text = value.Get().ToString();
LostFocus += new EventHandler(update);
}
public abstract string GetValue();
}
As #flkes stated, a generic class is the way to go on this one. You could try something along these lines: (you can find a fine example Here)
public abstract class TextBoxBase
{
public abstract object GetMin();
public abstract object GetMax();
public abstract object GetValue();
}
public abstract class TextBox<T> : TextBoxBase
{
public T min { get; set; }
public T max { get; set; }
public T value { get; set; }
public virtual void SetTextBox(T mn, T mx, T val)
{
min = mn;
max = mx;
value = val;
}
public override object GetMin() { return min; }
public override object GetMax() { return max; }
public override object GetValue() { return value; }
}
public class TextBoxInt : TextBox<int>
{
public override void SetTextBox(int mn, int mx, int val)
{
min = mn;
max = mx;
value = val;
}
}
public class TextBoxFloat : TextBox<float>
{
public override void SetTextBox(float mn, float mx, float val)
{
min = mn;
max = mx;
value = val;
}
}
Related
As shown in the first class displayed, I need to cast Activité to Réunion (Réunion extends Activité) but the compiler tells me that I can't. Why? I'll put a scheme so you can better understand my classes structure and also all my other classes. Thank you.
class Employé<T>
{
private string nom;
private Local bureau;
private LinkedList<Activité<T>> activités;
public Employé(string nom, Local bureau)
{
this.nom = nom;
this.bureau = bureau;
}
public void AjouteActivité(params Activité<T>[] activités)
{
foreach(Activité<T> activité in activités)
{
if (activité as Réunion != null)
// here's the problem !!! ((Réunion)activité).EmployéConvoqués = activité;
}
}
}
Here's the scheme of my classes structure:
And here are the other classes:
abstract class Activité<T>
{
private string label;
private DateTime début, fin;
private T lieu;
private readonly int id;
private static int CPT = 0;
public Activité(string label, DateTime début, DateTime fin, T lieu)
{
this.label = label;
this.début = début;
this.fin = fin;
this.lieu = lieu;
this.id = ++CPT;
}
public override string ToString()
{
return $"{id} : {label}(de {début} à {fin}) - {DescriptionLieu()}";
}
public double Duree()
{
return fin.Subtract(début).TotalMinutes;
}
public int Id
{
//tester get; seulement
get
{
return id;
}
}
public T Lieu
{
get
{
return lieu;
}
}
public abstract string DescriptionLieu();
}
class ActivitéExtérieure : Activité<string>
{
public ActivitéExtérieure(string label, DateTime début, DateTime fin, string lieu) : base(label,début,fin,lieu) { }
public override string DescriptionLieu()
{
return Lieu;
}
}
class ActivitéInterne : Activité<Local>
{
public ActivitéInterne(string label, DateTime début, DateTime fin, Local lieu) : base(label,début,fin,lieu)
{
lieu.AjouteActivité(this);
}
public override string DescriptionLieu()
{
return $"local :: {Lieu.NumComplet}";
}
}
class Employé<T>
{
private string nom;
private Local bureau;
private LinkedList<Activité<T>> activités;
public Employé(string nom, Local bureau)
{
this.nom = nom;
this.bureau = bureau;
}
public void AjouteActivité(params Activité<T>[] activités)
{
foreach(Activité<T> activité in activités)
{
if (activité as Réunion != null)
((Réunion)activité).EmployéConvoqués = activité;
}
}
}
class Local
{
private int etage;
private int numero;
private bool possedeWifi;
private Dictionary<int, ActivitéInterne> historiquesActivités;
public int Numero
{
get
{
return numero;
}
set
{
if (value < 0 || value > 99)
throw new IndexOutOfRangeException();
else
numero = value;
}
}
public int NumComplet
{
get
{
return etage * 100 + numero;
}
}
public bool PossedeWifi
{
get
{
return possedeWifi;
}
}
public Local(int etage, bool possedeWifi, int numero)
{
this.etage = etage;
this.possedeWifi = possedeWifi;
Numero = numero;
}
public Local(int etage, int numero) : this(etage, true, numero) { }
public Local(int local, bool possedeWifi) : this(local / 100, possedeWifi, local % 100) { }
public void AjouteActivité(ActivitéInterne a)
{
historiquesActivités.Add(a.Id, a);
}
}
class Réunion : ActivitéInterne
{
private HashSet<Employé<Local>> employésConvoqués;
public Réunion(string label, DateTime début, DateTime fin, Local lieu) : base(label, début, fin, lieu) { }
public Employé<Local> EmployéConvoqués
{
set
{
employésConvoqués.Add(value);
}
}
}
The error message says that "cast is redundant". This is because you have already tested for "activité as Réunion != null". The compiler figures out that in the 'if' clause this condition is already true, therefore the cast is not meaningful. On the other hand you cannot access activité.EmployéConvoqués because the static type of activité is not Réunion.
All you have to do is introduce a new variable when testing the type. Like this:
if (activité is Réunion réunion) {
réunion.EmployéConvoqués = activité;
}
However if you try this you will see that the assignment cannot be done because you are trying to assign an activity to an Employé<Local>. These are not compatible types. Perhaps you meant something like
foreach (Activité<T> activité in activités) {
if (activité is Réunion réunion && this is Employé<Local> employéLocal) {
réunion.EmployéConvoqués = employéLocal;
}
}
Comment: in the definition of Réunion you are adding to HashSet<Employé<Local>> employésConvoqués when setting the property Employé<Local> EmployéConvoqués. From a style point of view this is strange because people generally expect a property of type Employé<Local> will represent a single Employé<Local> rather than a collection of Employé<Local>. I would suggest that you remove the setter and instead define
public void Ajoute( Employé<Local> employéConvoqué) {
this.employésConvoqués.Add(employéConvoqué);
}
I was trying to create simple event and below is the block of code but its not working. When I try to debug, as soon as we create Point object it is throwing "StackOverFlowException" at "Set" property(even before we assign the value p.x=10). What I am doing wrong?
using System;
namespace Workshop
{
public class Point
{
public int x
{
get { return x; }
set
{
x = value;
onPointeChanged();
}
}
public int y
{
get { return y; }
set
{
y = value;
onPointeChanged();
}
}
public event EventHandler pointchanged;
private void onPointeChanged()
{
if (pointchanged != null)
pointchanged(this, EventArgs.Empty);
}
}
public class Program
{
public static void Main(String[] args)
{
Point p = new Point();
p.pointchanged += HandleEvent;
p.x = 10;
}
public static void HandleEvent(object obj, EventArgs sender)
{
Console.WriteLine("Event Raised");
}
}
}
Thanks
You are calling the set method indefinitelly until you run out of stack memory. What you're doing with
x = value;
is you're calling the x property's setter, which in turn does x = value, so it calls itself, and so on, and so on for all eternity.
To fix this, introduce a field:
private int x;
public int X
{
get => x;
set
{
x = value;
OnPointChanged();
}
}
This is the proper way of creating properties with custom logic behind get and/or set. If you didn't have your OnPointChanged() logic you could just do
public int X { get; set; }
which would generate the following code for you under the hood:
private int x;
public int X { get => x; set => x = value; }
The problem is you are assigning the property a value in its own setter:
public int x
{
get { return x; }
set
{
x = value; // <-- see you are assigning `value` to your `x` property.
onPointeChanged();
}
}
This will loop over and over again ad infinitum. You need to create a backing field:
private int _myField;
public int BetterNameThanX
{
get { return _myField; }
set
{
_myField = value;
onPointeChanged();
}
}
You have defined properties and you return every own property which causes recursivity on get and set scopes. Try to define private attributes and expose it by properties:
public class Point
{
private int _x;
public int x
{
get { return _x; }
set
{
_x = value;
onPointeChanged();
}
}
private int _y;
public int y
{
get { return _y; }
set
{
_y = value;
onPointeChanged();
}
}
public event EventHandler pointchanged;
private void onPointeChanged()
{
if (pointchanged != null)
pointchanged(this, EventArgs.Empty);
}
}
I have classes that has multiple properties which have well-defined name and function but have the same implementation. For example:
class Stats
{
private int attack;
public int Attack
{
get =>
HasBuff ? attack + 1 : attack;
set
{
if (value < 1 || value > 10)
throw new ArgumentOutOfRangeException("Invalid value");
attack = value;
}
}
public int Defense {...}
public int Speed {...}
}
Where Defense and Speed are to be implemented just like Attack . How can I generalize this structure to avoid redundancy and make changes easier?
Make another class to generalize stats:
public class Stat
{
public bool HasBuff { get; set; }
private int _stat;
public int Score
{
get => HasBuff ? _stat + 1 : _stat;
set => _stat = value;
}
}
Then just use that for each of your skills:
public class CombatStats
{
public Stat Attack { get; } = new Stat();
public Stat Defense { get; } = new Stat();
public Stat Speed { get; } = new Stat();
}
Calling code would look like this:
var ninja = new Ninja();
ninja.skills = new CombatStats();
var attackStrength = ninja.skills.Attack.Score;
As further improvement, implicit operators can be used to avoid object creation and call to Score:
public class Stat
{
...
public static implicit operator int(Stat stat)
{
return stat.Score;
}
public static implicit operator Stat(int value)
{
return new Stat()
{
Score = value
};
}
}
This makes the change transparent to client code written w.r.t. to the example in the question:
ninja.skills = new CombatStats(){
Attack = 5,
Defense = 2
}
int attack = ninja.skills.Attack;
One approach to consider:
class Stats
{
// other existing code here
private int defense;
public int Defense
{
get
{
return GetValue(defense);
}
set
{
SetValue(value, ref defense);
}
}
private int GetValue(int value)
{
return HasBuff ? value + 1 : value;
}
private void SetValue(int value, ref int target)
{
if (value < 1 || value > 10)
throw new ArgumentOutOfRangeException("Invalid value");
target = value;
}
}
Attack etc will now be basically the same as Defence but passing in attack rather than defense to GetValue and SetValue.
I would go with composition
Stat:
public class Stats
{
private readonly StatProperty _defense;
private readonly StatProperty _attack;
private readonly StatProperty _speed;
public Stats()
{
_defense = new StatProperty(this);
_attack = new StatProperty(this);
_speed = new StatProperty(this);
}
public int Defense
{
get => _defense.Value;
set => _defense.Value = value;
}
public int Attack
{
get => _attack.Value;
set => _attack.Value = value;
}
public int Speed
{
get => _speed.Value;
set => _speed.Value = value;
}
public bool HasBuff { get; set; }
}
StatProperty:
public class StatProperty
{
public Stats Stats { get; }
public StatProperty(Stats stats)
{
Stats = stats;
}
private int _value = 1;
public int Value
{
get => Stats.HasBuff ? _value + 1 : _value;
set
{
if (value < 1 || value > 10)
throw new ArgumentOutOfRangeException("Invalid value");
_value = value;
}
}
}
I would need more details to know if it is the best option.
you also could make StatProperty as internal if don't want to show it outside of your library or nested private class if you want to use this just on the class Stats
I am a little lost here.
Basically, I need to access an array item, a string and display it. Here is the code.
namespace Test3_2_Practice
{
public partial class InterfaceImplementation : Form
{
//Array
ICombatant[] combatants = new ICombatant[2];
public InterfaceImplementation()
{
InitializeComponent();
}
private void btnTest_Click(object sender, EventArgs e)
{
combatants[0] = new PlayerCharacter ("Conan" , 500);
combatants[1] = new MonsterCharacter ("Bob" , 5);
combatants[2] = new MonsterCharacter ("Snake" , 15);
string output = "Fighters" + Environment.NewLine;
for (var i = 0; i < combatants.Length; i++)
{
var character = combatants[i];
output += "Character:" + combatants[i].
}
}
}
}
So I have my array, combatants composed of two types of instances. I want to access the name, "Conan" and add it to a string for output. How do I go about doing that? Here is the rest of the code if that helps. Thanks!
namespace Test3_2_Practice
{
//Interface
interface ICombatant
{
int TakeDamage(int damageAmount);
string GetHealthDisplay();
}
class PlayerCharacter : ICombatant
{
private string characterName;
private int currentHealth;
private int maxHealth;
public string CharacterName
{
get { return characterName; }
set { characterName = value; }
}
public int CurrentHealth
{
get { return currentHealth; }
set { currentHealth = value; }
}
public int MaxHealth
{
get { return maxHealth; }
set { maxHealth = value; }
}
public PlayerCharacter(string characterName, int maxHealth)
{
CharacterName = characterName;
CurrentHealth = MaxHealth = maxHealth;
}
//Damage Class
public int TakeDamage(int damageAmount)
{
if (damageAmount > currentHealth)
{
damageAmount = currentHealth;
return damageAmount;
}
else
{
currentHealth = currentHealth - damageAmount;
return damageAmount;
}
}
//Health Class
public string GetHealthDisplay()
{
return ("Health " + CurrentHealth.ToString() + "/" + MaxHealth).ToString();
}
}
class MonsterCharacter : ICombatant
{
private string monsterName;
private int health;
public string MonsterName
{
get { return monsterName; }
set { monsterName = value; }
}
public int Health
{
get { return health; }
set { health = value; }
}
public MonsterCharacter(string monsterName, int health)
{
MonsterName = monsterName;
Health = health;
}
//Damage Class
public int TakeDamage(int damageAmount)
{
if(damageAmount > health)
{
damageAmount = health;
return damageAmount;
}
else
{
health = health - damageAmount;
return damageAmount;
}
}
//Health Class
public string GetHealthDisplay()
{
return "Health " + Health;
}
}
}
Actually, since name is common to all implementer of interface that Name property should be included to interface itself like
interface ICombatant
{
int TakeDamage(int damageAmount);
string GetHealthDisplay();
public string CharacterName
{
get;
set;
}
}
In your current scenario, you will have to cast it specific concrete type before accessing it
var character = combatants[i];
if(character is PlayerCharacter)
output += "Character:" + ((PlayerCharacter)character).CharacterName;
It's better to make a good use of your interface. Create a new method in your interface:
interface ICombatant
{
int TakeDamage(int damageAmount);
string GetHealthDisplay();
string GetCombatantName(); // added this
}
Then implement in both classes which implements it:
class PlayerCharacter : ICombatant
{
// ... a lot of code ...
public string GetCombatantName()
{
return String.Format("Character: {0}", this.CharacterName);
}
}
class MonsterCharacter: ICombatant
{
// ... a lot of code ...
public string GetCombatantName()
{
return String.Format("Monster: {0}", this.MonsterName);
}
}
And use it like this:
private void btnTest_Click(object sender, EventArgs e)
{
combatants[0] = new PlayerCharacter("Conan", 500);
combatants[1] = new MonsterCharacter("Bob", 5);
combatants[2] = new MonsterCharacter("Snake", 15);
string output = "Fighters" + Environment.NewLine;
foreach (var combatant in combatants)
{
output += combatant.GetCombatantName();
}
}
So if one day you get ten distinct types of ICombatant (like AnimalCharacter, VirusCharacter), you don't have to nest a lot of ifs to check and cast types to get the proper property.
Interfaces are meant exactly to avoid this kind of stuff, hiding the implementation details.
So at begining I like to set up some variables, which will later used. I am building some graph moving parts, where I must set up Step for every movement (if X change for 1 then Value change 1*Step ... bla bla).
I have MainWindowViewModel (short version):
public class MainWindowViewModel : ViewModelBase
{
public MainWindowViewModel()
{
// Initialization
Step = 3;
}
}
DiagramObject Class:
public abstract class DiagramObject : ViewModelBase
{
public abstract double X { get; set; }
public abstract string Xmeaning { get; set; }
public abstract double Y { get; set; }
public abstract string Ymeaning { get; set; }
}
So there inside I have defined "Steps":
public class DiagramNode : DiagramObject
{
public int xstep = 3;
public int ystep = 1;
public int xstepvalue = 5;
public int ystepvalue = 5;
private double _x;
public override double X
{
get { return _x; }
set
{
//"Grid Snapping"
_x = (Math.Round(value / xstep)) * xstep;
NotifyPropertyChanged("X");
double minutes = (_x / xstep) * xstepvalue;
TimeSpan interval = TimeSpan.FromMinutes(minutes);
_xmeaning = interval.ToString();
NotifyPropertyChanged("Xmeaning");
}
}
private string _xmeaning;
public override string Xmeaning
{
get { return _xmeaning; }
set
{
//"Grid Snapping"
_xmeaning = value;
NotifyPropertyChanged("Xmeaning");
}
}
private double _y;
public override double Y
{
get { return _y; }
set
{
//"Grid Snapping"
_y = (Math.Round(value / ystep)) * ystep;
NotifyPropertyChanged("Y");
double keks = (_y / ystep) * ystepvalue;
_ymeaning = keks.ToString();
NotifyPropertyChanged("Ymeaning");
}
}
private string _ymeaning;
public override string Ymeaning
{
get { return _ymeaning; }
set
{
//"Grid Snapping"
_ymeaning = value;
NotifyPropertyChanged("Ymeaning");
}
}
}
My question is How to update "xstep", "ystep" and others steps inside DiagramNode class from MainWindowViewModel at beginning of the program?
So when I start the program step will be defined and updated into DiagramNode class - now I have defined direct in class.
I hope that I give enough code for understanding the concept (if not say so). If any question please ask.
Your MainWindowViewModel will need to have an instance of the DiagramNode class instantiated so that it can access the properties to modify them.
public class MainWindowViewModel : ViewModelBase
{
DiagramNode myDiagramNode = new DiagramNode();
public MainWindowViewModel()
{
// Initialization
Step = 3;
myDiagramNode.xstep = 3;
}
}
Typically, though, it is a better practice to have variables like xstep and ystep to be set as private, and have accessors which can handle the setting/getting of the values, like so
public class DiagramNode : DiagramObject
{
private int xstep;
public int XStep
{
get { return this.xstep; }
set { this.xstep = value; }
}
...
}
public class MainWindowViewModel : ViewModelBase
{
DiagramNode myDiagramNode = new DiagramNode();
public MainWindowViewModel()
{
myDiagramNode.XStep = 3;
}
}
You could set them via a constructor overload
public class DiagramNode(int xstep, int ystep)
{
// set your values
}