How do Setter and Getter methods work? - c#

Before I started encapsulation and learn how to use properties, I was looking at Setters and Getters methods.
I understood how SetID and GetID methods works but I wasn't sure about SetName, GetName and GetPassMark methods.
using System;
public class Student
{
private int _id;
private string _Name;
private int _PassMark = 35;
public void SetId(int Id)
{
if (Id<=0)
{
throw new Exception("Student Id cannot be negative");
}
this._id = Id;
}
public int GetId()
{
return this._id;
}
public void SetName(string Name)
{
if(string.IsNullOrEmpty(Name))
{
throw new Exception("Name cannot be null or empty");
}
this._Name = Name;
}
public string GetName()
{
if(string.IsNullOrEmpty(this._Name))
{
return "No Name";
}
else
{
return this._Name;
}
}
public int GetPassMark()
{
return this._PassMark;
}
}
public class Program
{
public static void Main()
{
Student C1 = new Student();
C1.SetId(101);
C1.SetName("Mark");
Console.WriteLine("ID = {0}" , C1.GetId());
Console.WriteLine("Student Name = {0}", C1.GetName());
Console.WriteLine("PassMark = {0}", C1.GetPassMark());
}
}
When I looked at SetName, I understood that if the string is either empty or null, we throw exception and otherwise this._Name = Name.
But when I looked at GetName, I didn't really understand why there is the if statement.
If Name was null or empty, there wouldn't have been this._Name as we throw exception in SetName.
Can't we just write down return this._Name in GetName?
Also in GetPassMark method why is this. necessary in return this._PassMark?

Because _Name is not being set when you are creating the object. So there is a possibility that a Student object will have null _Name. You can fix it by setting the _Name in the constructor, then you can just return it.
Many people prefer to use this even when it's not really necessary since it makes the code more obvious. It's just a syntactical preference.

Related

Casting an object to its class

I am trying to create some classes with two variables. One of the variables is Name the other one is Value. For each class value can be different type of variables (int , double or string).
I want to store instances of these classes in a List so I placed the classes under an abstract class.
Then inside a foreach loop I want to use the Value of these instances but I need them casted into their original type so that the param.Set function will accept it.
My code is like this:
List<ElementProperty> parameters = new List<ElementProperty>();
//I add my parameters to the list.
parameters.Add(new ElementProperty.String("TestName", "TestVariable"));
parameters.Add(new ElementProperty.Integer("TestName", 10));
//I want to make this foreach loop shorter and more proper
foreach (var parameter in parameters)
{
Parameter param = el.LookupParameter(parameter.Name);
if (parameter is ElementProperty.Boolean)
{
param.Set(((ElementProperty.Boolean)parameter).Value);
//param.Set only accepts int double and string
}
else if (parameter is ElementProperty.Double)
{
param.Set(((ElementProperty.Double)parameter).Value);
}
else if (parameter is ElementProperty.Integer)
{
param.Set(((ElementProperty.Integer)parameter).Value);
}
else if (parameter is ElementProperty.String)
{
param.Set(((ElementProperty.String)parameter).Value);
}
}
public abstract class ElementProperty
{
public string Name;
public object Value;
public class Integer : ElementProperty
{
public new int Value;
public Integer(string Name, int Value)
{
this.Name = Name;
this.Value = Value;
}
}
public class Double : ElementProperty
{
public new double Value;
public Double(string Name, double Value)
{
this.Name = Name;
this.Value = Value;
}
}
public class String : ElementProperty
{
public new string Value;
public String(string Name, string Value)
{
this.Name = Name;
this.Value = Value;
}
}
public class Boolean : ElementProperty
{
public new int Value;
public Boolean(string Name, bool Value)
{
this.Name = Name;
if (Value is false)
{
this.Value = 0;
}
else
{
this.Value = 1;
}
}
}
}
Is there a better option? Any suggestion would help a lot.
Thank you.
I prefer using Interfaces for this, but you could do something like this:
// ...
foreach (var parameter in parameters)
{
parameter.SetTo(param); // Call same interface
}
// ...
In each of those concrete classes:
public class Integer : ElementProperty
{
public new int Value;
public Integer(string Name, int Value)
{
this.Name = Name;
this.Value = Value;
}
public void SetTo(Parameter p)
{
p.Set(this.Value); // calls correct overload
}
}
This works completey without switch/case or if/else chains.
However, be aware that the urge to use this pattern may be a hint to underlying design issues. Which is the reason it is sometimes perceived as a "code smell".

How to make a properly make setter edit class members

I am trying to make a setter for the public property of the private member age. It operates so that if the age you are trying to input is less than zero, the program should set it to zero and give you a basic message. However, this setter will literally let any negative number slip past it. If you try to edit it in the constructor, the setter doesn't even activate. But if you make an instance of the age class than try to edit that instances class, you can. However, it will let numbers less than zero pass through, and send the message "Viable", meaning it is a viable number. Here is the Person class the age member, property, constructor, etc. is located in.
namespace HopeThisWorks
{
class Person
{
private int age;
public int Age
{
get
{
return age;
}
set
{
if(age >= 0)
{
age = value;
System.Console.WriteLine("Viable");
}
else
{
age = 0;
System.Console.WriteLine("Not Viable");
}
}
}
public Person(int age)
{
this.age = age;
}
}
}
Here is the main method:
using System;
namespace HopeThisWorks
{
class Program
{
static void Main(string[] args)
{
Person p1 = new Person(1);
p1.Age = -1;
}
}
}
Any help would be muchly appreciated. Thank you!
Here's the working thing
using System;
public class Program
{
public static void Main()
{
var p = new Person(-5);
}
}
class Person
{
private int _age;
public int Age
{
get {return _age;}
set
{
if (value >= 0)
{
_age = value;
System.Console.WriteLine("Viable");
}
else
{
_age = 0;
System.Console.WriteLine("Not Viable");
}
}
}
public Person(int age)
{
Age = age;
}
}
In this case result will be Not Viable printed out.
Explanation is in Mark's comment.

property private set crashes unity

I have a custom class that gets some data from the web.
When I get this data I want to set it to the value of a property but when I do this unity crashes. The commented line generates the crash without this line everything works fine. See my code below:
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
public class GetDB
{
private readonly Main m;
private readonly string Url;
public string DBData {
get
{
if(DBData == null)
return null;
else
return DBData;
}
private set
{
DBData = value;
}
}
public GetDB(Main m, string url)
{
this.m = m;
this.Url = url;
}
public void GetServerData(){
m.StartCoroutine(GetText(Url, (result) =>{
this.DBData = result; //THIS LINE CRASHES UNITY
Debug.Log(result);
}));
}
IEnumerator GetText(string url, Action<string> result) {
UnityWebRequest www = UnityWebRequest.Get(url);
yield return www.SendWebRequest();
if(www.isNetworkError || www.isHttpError) {
Debug.Log(www.error);
}
else {
if (result != null)
result(www.downloadHandler.text);
}
}
}
How would I go about fixing this, and what exactly is happening here?
If anything is unclear let me know so I can clarify.
You have to use a backing field for the property:
string _dbData;
public string DBData
{
get
{
if(_dbData == null)
return null;
else
return _dbData;
}
private set
{
_dbData= value;
}
}
A property is just syntactic sugar for a getter and setter methods. So you can rewrite your property like:
public string GetDBData()
{
if(_dbData == null)
return null;
else
return _dbData;
}
public void SetDBData(string value)
{
_dbData = value;
}
The way you have implemented the property:
public void SetDBData(string value)
{
// you will never get out of here
SetDBData(value);
}
Properties act as accessors for variables. What is happening in your case is basically an endless loop - whenever somebody tries to get the value of your property, it keeps returning the property itself. Instead, you want a backing field _dbData:
private string _dbData;
public string DBData
{
get
{
return _dbData;
}
private set
{
_dbData = value;
}
}
Now your property controls the accesss to this field.
Your accessor can be really simplified.
Doing :
get
{
if(DBData == null)
return null;
else
return DBData;
}
Will provide exactly the same result than doing :
get
{
return DBData; //if DBData is null, it will return null
}
So, you can write your accessor that way :
public string DBData
{
get;
private set;
}

Debug and properties loading

I have an object that represents a record of a table in my database, for example 'Project'.
My User class has different properties which are the records of other tables, for example, 'Client' or 'Accountancy'. Those also have properties to related tables.
Each of these properties returns a local value (already loaded) if not null, and there is no loaded information, it generates a request to get this value from database.
My issue is the following : when I set a breakpoint, and check the object in the debug window, it loads automatically all the values of the properties, and so, requests the database.
With this scenario, I cannot have a precise and static snapshot of my object at the moment.
Is there a way, in code, not to go through this part of code if in debug window ?
For instance, something like that:
public MyBaseObject GetProperty<T>(string columnName_, string alias_ = null) where T : MyBaseObject, new()
{
var ret = GetExtract<T>(columnName_, alias_);
// if the data are loaded
if (ret.Id != null)
return ret;
// Fake boolean I would like
if(InDebugWindowAfterAbreakPointForInstance)
return ret;
else
ret = LoadFromDatabase<T>(columnName_, alias_)
return ret;
}
I've found different attributes with the debugger, like the DebuggerStepperBoundaryAttribute, but nothing that could do something like that.
In situations like this the only way I know of is to use a DebuggerTypeProxy for each of your types then in that proxy have it access the backing field directly instead of going through the property that causes the database lookup to happen.
Here is a simple example program.
public class Program
{
public static void Main(string[] args)
{
var client = new Client();
Debugger.Break();
Debugger.Break();
}
}
[DebuggerTypeProxy(typeof(ClientDebugView))]
public class Client : MyBaseObject
{
private string _firstName;
private string _lastName;
public string FirstName
{
get
{
if (_firstName == null)
_firstName = GetProperty<string>("FirstName");
return _firstName;
}
set
{
if (Equals(_firstName, value))
return;
_firstName = value;
UpdateDatabase(_firstName, "FirstName");
}
}
public string LastName
{
get
{
if (_lastName == null)
_lastName = GetProperty<string>("LastName");
return _lastName;
}
set
{
if (Equals(_lastName, value))
return;
_lastName = value;
UpdateDatabase(_lastName, "LastName");
}
}
internal class ClientDebugView : MyBaseObjectDebugView
{
private readonly Client _client;
public ClientDebugView(Client client)
: base(client)
{
_client = client;
}
public string FirstName
{
get { return _client._firstName; }
}
public string LastName
{
get { return _client._lastName; }
}
}
}
[DebuggerTypeProxy(typeof(MyBaseObjectDebugView))]
public class MyBaseObject
{
private Guid? _id;
public Guid? Id
{
get
{
if (_id == null)
_id = GetProperty<Guid?>("Id");
return _id;
}
set
{
if (Equals(_id, value))
return;
_id = value;
UpdateDatabase(_id, "Id");
}
}
//Fake loading data from a database.
protected T GetProperty<T>(string columnName)
{
object ret = null;
switch (columnName)
{
case "Id":
ret = Guid.NewGuid();
break;
case "LastName":
ret = "Smith";
break;
case "FirstName":
ret = "John";
break;
default:
ret = null;
break;
}
return (T)ret;
}
protected void UpdateDatabase<T>(T id, string s)
{
throw new NotImplementedException();
}
internal class MyBaseObjectDebugView
{
private readonly MyBaseObject _baseObject;
public MyBaseObjectDebugView(MyBaseObject baseObject)
{
_baseObject = baseObject;
}
public Guid? Id
{
get { return _baseObject._id; }
}
}
}
If you view the client object in the debugger you will see it leaves the backing fields null between the two breakpoints unless you open the "Raw View" at the first breakpoint.

Getting property values from a static class using reflection

I have a class that is used for storing user data to a file. It works well, but can't really be placed into a PCL library easily. Outside of the PCL, it's all fine.
The class looks like this
public static class UserData
{
public static object GetPropertyValue(this object data, string propertyName)
{
return data.GetType().GetProperties().Single(pi => pi.Name == propertyName).GetValue(data, null);
}
public static object SetPropertyValue<T>(this object data, string propertyName, T value)
{
data.GetType().GetProperties().Single(pi => pi.Name == propertyName).SetValue(data, value);
return new object();
}
private static string pUserSettingsFile;
private static UserSettings userSetting;
public static bool AccountEnabled
{
get
{
return UserSettings.account_enabled;
}
set
{
UserSettings settings = UserSettings;
settings.account_enabled = value;
UserSettings = settings;
}
}
public static UserSettings UserSettings
{
get
{
if (userSetting == null)
{
if (File.Exists(UserSettingsFile))
{
userSetting = Serializer.XmlDeserializeObject<UserSettings>(UserSettingsFile);
}
else
{
userSetting = new UserSettings();
Serializer.XmlSerializeObject(userSetting, UserSettingsFile);
}
}
return userSetting;
}
set
{
if (value == null)
{
throw new ArgumentNullException("value is null!");
}
userSetting = value;
if (File.Exists(UserSettingsFile))
{
File.Delete(UserSettingsFile);
}
Serializer.XmlSerializeObject(userSetting, UserSettingsFile);
}
}
public static string UserSettingsFile
{
get
{
if (string.IsNullOrEmpty(pUserSettingsFile))
{
pUserSettingsFile = Path.Combine(GroupShootDroid.Singleton.ContentDirectory, "UserSettings.xml");
}
return pUserSettingsFile;
}
}
#endregion
}
public class UserSettings
{
public bool account_enabled { get; set; }
public string address { get; set; }
public string country { get; set; }
}
It's not rocket science, but does what I need it to do.
What I'm trying to do is use the Get/SetPropertyValue methods to return or set any of the properties within the class.
Currently, to access the Get/SetPropertyValue methods I'm using this
public string GetStringValue(string valToGet)
{
string rv = (string)UserData.GetPropertyValue(valToGet);
return rv;
}
public void SetStringValue(string name, string val)
{
UserData.SetPropertyValue(name, val);
}
On compiling though, the GetPropertyValue method is giving an error that No overload for method GetPropertyValue takes 1 argument with the SetPropertyValue complaining that there isn't an overload that takes 2
I'm not sure that the code I'm using will do what I need it to do (from what I've read on here it should be), but I'm more perplexed as to why the errors are showing.
Is there a better way to do what I'm trying to do? The application is a Xam.Forms app, so the PCL accesses the class through an interface using injection.
You are defining extension method, you need an instance of the class to call them:
var o = new Object();
string rv = (string)o.GetPropertyValue(valToGet);
// or, but no sure
string rv = (string)UserData.GetPropertyValue(o, valToGet);
or more probably in your case:
public string GetStringValue(string valToGet)
{
string rv = (string)this.GetPropertyValue(this, valToGet);
//or
//string rv = (string)UserData.GetPropertyValue(this, valToGet);
return rv;
}
I think you're getting confused between the UserData class and the object class. Your extension methods extend object.

Categories