c# encapsulation Get/ Set - c#

looking for some clarification on Get / Set. I have this code which I use to create my objects..However I want to have some validation in with the length and width (both need to be greater than some number as example). I believe Get / Set is the way to go and I have used this when changing fields in an instance - but how do I do it at the Instantiation stage?
class Room
{
public Double dblLength;
public Double dblWidth;
public Room (Double _dblLength, Double _dblWidth)
{
dblLength = _dblLength;
dblWidth = _dblWidth;
}

Turn fields into properties; implement validation within corresponding set:
class Room
{
private Double m_DblLength;
private Double m_DblWidth;
public Room (Double _dblLength, Double _dblWidth) {
DblLength = _dblLength;
DblWidth = _dblWidth;
}
public Double DblLength {
get {
return m_DblLength;
}
set {
//TODO: validation here
if (value < 0)
throw new ArgumentOutOfRangeException("value");
m_DblLength = value;
}
}
public Double DblWidth {
get {
return m_DblWidth;
}
set {
//TODO: validation here
if (value < 0)
throw new ArgumentOutOfRangeException("value");
m_DblWidth = value;
}
}

Here's an example, based on Alex's comment. Personally I'd also get rid of the underscores and 'dbl' prefix, but I've left them in to match the question.
You can't return a failure message from a constructor, so throw an exception.
class Room
{
private Double dblLength;
private Double dblWidth;
public Room (Double _dblLength, Double _dblWidth)
{
if (_dblLength < _dblWidth)
{
throw new ArgumentException("length must be more than width");
}
dblLength = _dblLength;
dblWidth = _dblWidth;
}
}
This is appropriate if it indicates that the programmer using your class doesn't understand it. However if there is a good chance of this happening at run time, you might be better to have a 'hasError' flag in the object that prevents it from being saved, or doing whatever it does.
class Room
{
private Double dblLength;
private Double dblWidth;
public bool HasError {get;}
public Room (Double _dblLength, Double _dblWidth)
{
if (_dblLength < _dblWidth)
{
HasError = true;
}
dblLength = _dblLength;
dblWidth = _dblWidth;
}
public Save()
{
if (HasError) return;
// Otherwise do the save;
}
}

If your class is immutable, the easiest is:
class Room
{
public double Length { get; }
public double Width { get; }
public Room(double length, double width)
{
// Validation here, for instance throw exception if length <= 0
Length = length;
Width = width;
}
}
Using C# 6's readonly auto properties.

You can change the fields into properties. When you have changed the fields into properties you can then validate the value which will be set to the according property and if it does not meet the requirements you can throw an exception.
Example:
class Room
{
private double _dblLength;
private double _dblWidth;
public double DblLength {
get
{
return _dblLength;
}
set
{
//TODO -> Do validation
//the keyword value represents the value that you want to pass to the property
if(value < 0)
{
throw new ArgumentOutOfRangeException("message");
}
_dblLength = value;
}
}
public double DblWidth
{
get
{
return _dblWidth;
}
set
{
//TODO -> Do validation
//the keyword value represents the value that you want to pass to the property
if (value < 1)
{
throw new ArgumentOutOfRangeException("message");
}
_dblWidth = value;
}
}
public Room(Double _dblLength, Double _dblWidth)
{
DblLength = _dblLength;
DblWidth = _dblWidth;
}
}
Another good thing to do is if you want the properties to be set only when an instance is created(only through the constructor) you can make the setter private like so:
class Room
{
private double _dblLength;
private double _dblWidth;
public double DblLength {
get
{
return _dblLength;
}
private set
{
//TODO -> Do validation
//the keyword value represents the value that you want to pass to the property
if(value < 0)
{
throw new ArgumentOutOfRangeException("message");
}
_dblLength = value;
}
}
public double DblWidth
{
get
{
return _dblWidth;
}
private set
{
//TODO -> Do validation
//the keyword value represents the value that you want to pass to the property
if (value < 1)
{
throw new ArgumentOutOfRangeException("message");
}
_dblWidth = value;
}
}
public Room(Double _dblLength, Double _dblWidth)
{
DblLength = _dblLength;
DblWidth = _dblWidth;
}
}
This is possible because properties are just syntax sugar provided to us by C#. When this code is compiled the compiler will create two methods Get and Set for each property. Thus if you put an access modifier on the getter or setter the compiler will take that in mind and when it compiles the code, it will put the modifier which you have specified. However, if no specific modifier is specified the compiler will take the modifier of the property itself in the above case the Get method will be public and the Set method will be private. After compilation the code will look something like this:
class Room
{
private double _dblLength;
private double _dblWidth;
public Room(Double _dblLength, Double _dblWidth)
{
SetDblLength(_dblLength);
SetDblWidth(_dblWidth);
}
public double GetDblLength()
{
return _dblLength;
}
private void SetDblLength(double value)
{
if (value < 0)
{
throw new ArgumentOutOfRangeException("message");
}
_dblLength = value;
}
public double GetDblWidth()
{
return _dblWidth;
}
private void SetDblWidth(double value)
{
if (value < 0)
{
throw new ArgumentOutOfRangeException("message");
}
_dblWidth = value;
}
}

Related

Accessing class's properties after using List<>

I'm a beginner in C# and I have a particular question that is related in inheritance and polymorphism based on using classes. The assignment that I'm working is a bank account and that I have to use three classes-one is a base class while the other two are derived classes.
The base class is known as "BankAccount" and the two derived classes are"CheckingAccount" and "SavingsAccount". Furthermore, I have declared objects for "CheckingAccount" and "SavingAccount" and that they are stored in a List class. Afterwards, I'm trying to populate my assignment's GUI's labels accordingly based from the derived class's properties by using a combobox's "SelectedIndexChange" event.
The problem is that somehow the program doesn't check if the list class's stored elements are recognized as a particular type. Below of this contains my code for the program and the classes.
private void comboBoxAccountNumber_SelectedIndexChanged(object sender, EventArgs e)
{
if (selectedBankAccount[0] is CheckingAccount)
{
labelOwnerID.Text = selectedBankAccount[0].AccountNumber;
labelBalance.Text = selectedBankAccount[0].Balance.ToString("c");
}
else if (selectedBankAccount[1] is CheckingAccount)
{
labelOwnerID.Text = selectedBankAccount[1].AccountNumber;
labelBalance.Text = selectedBankAccount[1].Balance.ToString("c");
}
}
List<BankAccount> selectedBankAccount = new List<BankAccount> ();
SavingsAccount savs1_Account;
CheckingAccount chek1_Account;
SavingsAccount savs2_Account;
CheckingAccount chek2_Account;
private void FormBankOfYourSelf_Load(object sender, EventArgs e)
{
savs1_Account = new SavingsAccount("0001", "31-1000", 100m, 0.01);
chek1_Account = new CheckingAccount("0001", "44-1000", 250m, true);
savs2_Account = new SavingsAccount("0002", "31-1001", 1000m, 0.0125);
chek2_Account = new CheckingAccount("0002", "44-1001", 500m, false);
selectedBankAccount.Add(chek1_Account);
selectedBankAccount.Add(chek2_Account);
comboBoxAccountNumber.Items.Add(selectedBankAccount[0].AccountNumber);
comboBoxAccountNumber.Items.Add(selectedBankAccount[1].AccountNumber);
}
public abstract class BankAccount
{
// Fields - The data we want to store
// Naming convention for fields is to use underscore before the name
protected string _customerId;
protected string _accountNumber;
protected decimal _balance;
//Properties - Allow access to fields (Get/Set)
// Get = read access
// Set = write (modify) access
public string CustomerId
{
get { return _customerId; }
set { _customerId = value; }
}
public string AccountNumber
{
get { return _accountNumber; }
set { _accountNumber = value; }
}
public decimal Balance
{
get { return _balance; }
}
// Methods - The action or behaviors the class can do
// almost always, define the constructor and ToString methods
// Constructor creates (instantiates a new object)
public BankAccount(string customerId, string accountNumber, decimal initialBalance)
{
//fields are set = to the parameters(inputs from the form)
_customerId = customerId;
_accountNumber = accountNumber;
_balance = initialBalance;
}
public abstract bool Deposit(decimal depositAmount);
//{
// // If the depositAmount is less then 0 then RETURN false
// if (depositAmount <= 0)
// {
// return false;
// }
// // Otherwise, complete the deposit and RETURN true
// _balance += depositAmount;
// return true;
//}
public abstract bool Withdraw(decimal withdrawAmount);
//{
// // If the withdrawAmount is greater than the balance or less then or equal to 0
// // then RETURN false (don't allow withdrawal)
// if (withdrawAmount > _balance || withdrawAmount <= 0)
// {
// return false;
// }
// // Otherwise, complete the withdrawal and return true
// _balance -= withdrawAmount;
// return true;
//}
public class CheckingAccount : BankAccount
{
//private string _customerID;
//private string _accountNum;
//private decimal _initBalance;
private bool _overdraftProtection;
public CheckingAccount(string customerId, string accountNum, decimal initialBalance, bool overDraft)
:base(customerId, accountNum, initialBalance)
{
//_customerID = customerId;
//_accountNum = accountNum;
//_initBalance = initialBalance;
_overdraftProtection = overDraft;
}
public bool OverDraftProtection
{
get { return _overdraftProtection; }
set { _overdraftProtection = value; }
}
public override bool Deposit(decimal depositAmount)
{
if(depositAmount > 0)
{
_balance += depositAmount;
return true;
}
else
{
return false;
}
}
public override bool Withdraw(decimal withdrawAmount)
{
if(withdrawAmount <= _balance || withdrawAmount > 0 )
{
_balance -= withdrawAmount;
return true;
}
else
{
return false;
}
}
}
**Update: I noticed that when I run my program, even though I select different items within the combobox, it doesn't change the values to a selected item accordingly. Below is my program running with different items being selected.
First selected item in combobox
Second selected item in combobox
Your list is of type BankAccount so you need to cast the object to the specific inherited class you want to work with before the properties will become available
Using the is keyword and then the as keyword is expensive performance wise because you are basically casting twice. Best to use the as keyword and test for null
CheckingAccount account = selectedBankAccount[0] as CheckingAccount
if(account != null)
{
//account is of type CheckingAccount so the additional
//CheckingAccount properties should be available via the account variable
}
From posted comments it turns out the problem is that the code is not selecting the BankAccount selected in the ComboBox. Not knowing how the ComboBox is populated. The easiest way is to use the selected index assuming comboBoxAccountNumber is populated with the selectedBankAccount collection.
private void comboBoxAccountNumber_SelectedIndexChanged(object sender, EventArgs e)
{
BackAccount account = selectedBankAccount[comboBoxAccountNumber.SelectedIndex]
labelOwnerID.Text = account.AccountNumber;
labelBalance.Text = account.Balance.ToString("c");
}

Create reference to a primitive type field in class

I have a few classes which have some primitive fields and I would like to create a generalized wrapper for them in order to access their fields. This wrapper should somehow contain a reference to the fields of my classes so that I can read/write the values of these fields. The idea is to create a genralized architecture for these classes so that I dont have to write code for each of them. The classes have fields which have a number in them which will be used as an Id to access the fields.
This is some example code that might shed some light on my requirement. What I want in the end is to change the value of some field in the object of Fancy1 class without accessing the object itself but through its wrapper.
class Fancy1
{
public double level1;
public bool isEnable1;
public double level2;
public bool isEnable2;
public double level3;
}
class Fancy2
{
public double level4;
public bool isEnable4;
public double level6;
public bool isEnable6;
public double level7;
}
class FieldWrapper
{
public int id { get; set; }
public object level { get; set; }
public object isEnabled { get; set; }
public FieldWrapper(int id, object level, object isEnabled)
{
this.id = id;
this.level = level;
this.isEnabled = isEnabled;
}
}
class FancyWrapper
{
private Fancy scn;
public FancyWrapper(Fancy scn)
{
if (!(scn is Fancy))
throw new ArgumentException(scn.GetType().FullName + " is not a supported type!");
this.scn = scn;
}
private Dictionary<int, FieldWrapper> fieldLut = new Dictionary<int, FieldWrapper>();
private List<FieldWrapper> _fields { get { return fieldLut.Values.ToList(); } }
public List<FieldWrapper> fields
{
get
{
if (_fields.Count == 0)
{
foreach (System.Reflection.FieldInfo fieldInfo in scn.GetType().GetFields())
{
if (fieldInfo.FieldType == typeof(double))
{
int satId = getIdNr(fieldInfo.Name);
fieldLut.Add(satId, new FieldWrapper(satId, fieldInfo.GetValue(scn), true));
}
}
foreach (System.Reflection.FieldInfo fieldInfo in scn.GetType().GetFields())
{
if (fieldInfo.FieldType == typeof(bool))
{
int satId = getIdNr(fieldInfo.Name);
fieldLut[satId].isEnabled = fieldInfo.GetValue(scn);
}
}
}
return _fields;
}
}
private int getIdNr(string name)
{
System.Text.RegularExpressions.Match m = System.Text.RegularExpressions.Regex.Match(name, #"\d+");
return Int32.Parse(m.Value);
}
}
class Program
{
static void Main(string[] args)
{
Fancy1 fancy = new Fancy1();
fancy.level1 = 1;
fancy.isEnable1 = true;
fancy.level2 = 2;
fancy.isEnable2 = false;
fancy.level3 = 3;
FancyWrapper wrapper = new FancyWrapper(fancy);
wrapper.fields[2].level = 10;
// fancy.level2 should somehow get the value I set via the wrapper
Console.WriteLine(fancy.level2);
Console.ReadLine();
}
}
EDIT: Fancy classes cannot be changed since they are part of an interface!
Depending on how many Fancy classes you are dealing with, you could create an adapter/facade class for each the expose a common interface. eg:
class Fancy1
{
public double level1;
public bool isEnable1;
public double level2;
public bool isEnable2;
public double level3;
}
public class FieldWrapper
{
private Action<double> _levelSetter;
private Func<double> _levelGetter;
private Action<bool> _enableSetter;
private Func<bool> _enableGetter;
public double level { get { return _levelGetter(); } set { _levelSetter(value); }}
public bool isEnabled { get { return _enableGetter(); } set { _enableSetter(value); }}
internal FieldWrapper(Func<double> levelGetter, Action<double> levelSetter, Func<bool> enableGetter, Action<bool> enableSetter)
{
_levelGetter = levelGetter;
_levelSetter = levelSetter;
_enableGetter = enableGetter;
_enableSetter = enableSetter;
}
}
abstract class FancyWrapper
{
public FieldWrapper[] Fields { get; protected set; }
}
class Fancy1Wrapper : FancyWrapper
{
private Fancy1 _fancy1;
public Fancy1Wrapper(Fancy1 fancy1)
{
_fancy1 = fancy1;
this.Fields = new[] { new FieldWrapper(() => fancy1.level1, level => _fancy1.level1 = level, () => _fancy1.isEnable1, enable => _fancy1.isEnable1 = enable),
new FieldWrapper(() => fancy1.level2, level => _fancy1.level2 = level, () => _fancy1.isEnable2, enable => _fancy1.isEnable2 = enable), };
}
}
Or you could invest 5 minutes learning data structures. Consider following example:
var levels = new Dictionary<int, bool>
{
{1, true},
{2, false}
};
if (levels[1])
{
//will run, because level 1 is true
}
if (levels[2])
{
//will not run, because level 2 is false
}
if (levels.ContainsKey(3) && levels[3])
{
//will not run, because dictionary does not contain entry for key 3
}
levels.Add(3, false);
if (levels.ContainsKey(3) && levels[3])
{
//will not run, because level 3 is false
}
levels[3] = true;
if (levels.ContainsKey(3) && levels[3])
{
//will run, because level 3 is true
}
That may seem like what you want, but it really isn't. It is extremely awkward on any number of levels. More specifically, pointers are generally rather "Un-C#-like" and having to know about these numbers defeats the point of having separate classes to begin with.
Think closely about what you want to accomplish. If you're having problems translating it into code, we're here to help. :)

Using loop to get value in different variable in a class C#

I have a class with a different variable like this:
namespace Model
{
public class Example
{
private double _var1;
private double _var2;
private double _var3;
private double _var4;
private double _var5;
public double Var1
{
get { return _var1; }
set { _var1 = value; }
}
public double Var2
{
get { return _var2; }
set { _var2 = value; }
}
public double Var3
{
get { return _var3; }
set { _var3 = value; }
}
public double Var4
{
get { return _var4; }
set { _var4 = value; }
}
public double Var5
{
get { return _var5; }
set { _var5 = value; }
}
}
}
A method will using this class to be a model and assign a value to every variable in it.
How to get all the value in different variable inside this class? Thank you.
EDIT
I'm using Hassan code and the code look like this:
foreach (PropertyInfo var in typeof(Example).GetProperties())
{
if (var.Name.Contains("Var"))
{
_dataTable.Rows.Add(_dateDailyBalance, var.GetValue(_justANormalModelOfExample, null));
}
}
but it returns all zero. the expected returns is some value. Why?
Add System.Reflection namespace:
For example setting 0.1 to each property.
Example obj = new Example();
Type type = obj.GetType();
PropertyInfo[] properties = type.GetProperties();
double d = 0.1;
foreach (PropertyInfo property in properties)
{
property.SetValue(obj, d, null);
}
As Hassan said, if you're dead set on using each as different variables, reflection would be the way to loop through the variables.
But if they're all doubles, why not array them? You could do this a number of ways...
namespace Model
{
public class Example : IEnumerable<double>
{
private double vars = new double[5];
protected double this[int ix]
{
get { return vars[ix]; }
set { vars[ix] = value; }
}
public IEnumerator<double> GetEnumerator()
{
return vars;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return ((IEnumerable<double>)this).GetEnumerator();
}
}
}
This allows you to index an instance of the class like an array.
because all of your properties are in same type, it is better to use indexer. here is an easy example of indexer, try to write it for your code. (i made this example because it is easy to understand)
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
MyClass me = new MyClass();
//you can use me[index] = value for accessing the index of your indexer
for (int i = 0; i < 3; i++)
{
MessageBox.Show(me[i]);
}
}
}
class MyClass
{
string[] name = { "Ali", "Reza", "Ahmad" };
public string this[int index]
{
get { return name[index]; }
set { name[index] = value; }
}
}
please let me know if you have any problem with understanding the code. and you need to change
string[]
to
double[]
for your code.
for more info see:
http://msdn.microsoft.com/en-us/library/6x16t2tx.aspx

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; }

foreach dictionary to check derived class

I have a base class Rules.cs. There are 2 derived classes RowRules.cs and ColumnRules.cs. I have another class Test.cs. This class has a Dictionary <int, Rules> which keeps adding the values. When I loop through the dictionary I need to know if the value is a RowRule or a ColumnRule. To better understand I have the code below.
Rules.cs
class Rules
{
private int m_timepointId = 0;
private int m_studyId = 0;
public int TimepointId
{
get { return m_timepointId; }
set { m_timepointId = value;}
}
public int StudyId
{
get { return m_studyId; }
set {m_studyId = value; }
}
}
RowRules.cs
class RowRules : Rules
{
private int m_row;
public int Row
{
get { return m_row; }
set { m_row = value; }
}
}
ColumnRules.cs
class ColumnRules: Rules
{
private int m_column;
public int Column
{
get { return m_column; }
set { m_column = value; }
}
}
In the main class I have
private Dictionary<int, Rules> m_testDictionary = new Dictionary<int, Rules>();
ColumnRules columnrules = new ColumnRules();
RowRules rowRules = new RowRules();
rowRules.Row = 1;
rowRules.StudyId = 1;
m_testDictionary.Add(1, rowRules);
columnRules.Column = 2;
columnRules.TimepointId = 2;
m_testDictionary.Add(2, columnRules);
foreach(.... in m_testDictionary)
{
//Need code here.
//if(... == RowRules)
{
}
}
Now, I need to know what value will go in the foreach loop. Also, I need to know whether that particular dictionary row is a RowRule or a ColumnRule. Hope I am clear with the question. Any help will be really appreciated.
There are a bunch of answers that are telling you to test the type using "is". That's fine, but in my opinion if you're switching off the type of an object, you're probably doing something wrong.
Typically, derived classes are used when you need additional and varied functionality from a base class. Moreover, ad-hoc polymorphism via virtual and abstract methods means that you can let the run-time figure out the type, leading to significantly cleaner code.
For example, in your case, you might want to make Rules an abstract class, with an abstract ApplyRule() method. Then, each subclass can implement the method, with the full knowledge of what it means to be a rule of that type:
public class Rules
{
private int m_timepointId = 0;
private int m_studyId = 0;
public int TimepointId
{
get { return m_timepointId; }
set { m_timepointId = value;}
}
public int StudyId
{
get { return m_studyId; }
set {m_studyId = value; }
}
// New method
public abstract void ApplyRule();
}
class RowRules : Rules
{
private int m_row;
public int Row
{
get { return m_row; }
set { m_row = value; }
}
public override void ApplyRule() { // Row specific implementation }
}
class ColumnRules : Rules
{
private int m_column;
public int Column
{
get { return m_column; }
set { m_column = value; }
}
public override void ApplyRule() { // Column specific implementation }
}
Now, your loop is just:
foreach(var kvp in m_testDictionary)
{
kvp.Value.ApplyRule();
}
This should work:
foreach(KeyValuePair<int, Rules> pair in m_testDictionary)
{
if(pair.Value is RowRule)
{
// do row rule stuff
}
if(pair.Value is ColumnRule)
{
// do row column rule stuff
}
}
Here is more information on the is keyword.
Try the following
foreach(var rule in in m_testDictionary.Values)
{
var rowRules = rule as RowRules;
if (rowRules != null) {
// It's a RowRules
continue;
}
var columnRules = rule as ColumnRules;
if (columnRules != null) {
// It's a ColumnRules
continue;
}
}
You can try this:
foreach(var key in m_testDictionary.Keys)
{
var value = m_testDictionary[key];
if(value is RowRules)
{
//test your code.....
}
}
does that code work? You have added the same key twice I believe. This is the code you wanted I believe:
foreach(int key in m_testDictionary.Keys)
{
RowRules row = m_testDictionary[key] as RowRules;
if(row !=null)
{
//code here:)
}
}

Categories