Related
This question already has answers here:
When do you use the "this" keyword? [closed]
(31 answers)
Closed 5 years ago.
The older apprentices in my company use "this." a lot.
Two weeks ago I started coding object-oriented and still don't get for what it is being used.
You need to understand what instance is first. Let's say you have an object:
public class House
{
public decimal Height { get; set; }
}
You can have multiple instances of it:
var smallHouse = new House { Height = 100M };
var bigHouse = new House { Height = 300M };
Each instance has its own value of Height. When you want to work with Height in a method of House, you need to refer to the current instance method is operating at (the one consumer called).
This can be done explicitly by using this as a special kind of variable that refers to this current instance:
public class House
{
public decimal Height { get; set; }
public bool IsItTooBig()
{
return this.Height > 200;
}
}
Or you can omit this and let C# guess that what you mean is the instance value:
public class House
{
public decimal Height { get; set; }
public bool IsItTooBig()
{
return Height > 200;
}
}
Programmers differ in opinion whether it's good or bad to be explicit there. If you follow capitalization conventions, you can distinguish instance state and method scope state (normal variables) by it.
There are cases where you absolutely need it, for example when you have naming conflict, or when you want to return current instance from a method:
public class House
{
public decimal Height { get; set; }
public House AddFloor()
{
Height += 100;
return this;
}
}
You should consider applying immutability in many of these cases though.
The keyword 'this' represents the instance of an object used to explicitly call a method, field or property of that instance.
Commonly used when your private fields have the same name as the parameters in a given method:
private string name;
public void SetName(string name) {
this.name = name;
}
When you want to refer to instance field within that class you use this, it can be omitted but there are cases it can not be omitted.
public class InstanceClass
{
int field = 10;
public void Method()
{
int field = 0;
Console.WriteLine(field); // outputs 0
Console.WriteLine(this.field); // outputs 10 because "this" refers to field.
}
}
if there is no declared local variable that conflicts with field name, "this" can be omitted.
public class InstanceClass
{
int _field = 10;
public void Method()
{
int field = 0;
Console.WriteLine(field);
Console.WriteLine(_field); // prefixed with _.
// no conflicts
// so "this" can be omitted.
}
}
another case where you can not omit this, is when you use indexer.
public class InstanceClass
{
private List<int> _source;
private int offset;
public int this[int index] // you use "this"
{
get => _source[index + offset]
set => _source[index + offset] = value;
}
public void Method()
{
var first = this[0]; // must use "this" to refer to indexer for this class.
}
}
"this" is used for calling constructor overloads too.
public class Foo
{
public Foo() : this(0)
{
Console.WriteLine("world");
}
public Foo(int param1)
{
Console.WriteLine("Hello");
}
}
//...
var foo = new Foo(); // outputs "Hello world"
"this" also refers to instance of class itself. so if you want to return instance of self you use this.
public class Foo
{
public Foo ReturnMe() // weird example.
{
return this;
}
}
How do you give a C# auto-property an initial value?
I either use the constructor, or revert to the old syntax.
Using the Constructor:
class Person
{
public Person()
{
Name = "Initial Name";
}
public string Name { get; set; }
}
Using normal property syntax (with an initial value)
private string name = "Initial Name";
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
Is there a better way?
In C# 5 and earlier, to give auto implemented properties an initial value, you have to do it in a constructor.
Since C# 6.0, you can specify initial value in-line. The syntax is:
public int X { get; set; } = x; // C# 6 or higher
DefaultValueAttribute is intended to be used by the VS designer (or any other consumer) to specify a default value, not an initial value. (Even if in designed object, initial value is the default value).
At compile time DefaultValueAttribute will not impact the generated IL and it will not be read to initialize the property to that value (see DefaultValue attribute is not working with my Auto Property).
Example of attributes that impact the IL are ThreadStaticAttribute, CallerMemberNameAttribute, ...
Edited on 1/2/15
C# 6 :
With C# 6 you can initialize auto-properties directly (finally!), there are now other answers that describe that.
C# 5 and below:
Though the intended use of the attribute is not to actually set the values of the properties, you can use reflection to always set them anyway...
public class DefaultValuesTest
{
public DefaultValuesTest()
{
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(this))
{
DefaultValueAttribute myAttribute = (DefaultValueAttribute)property.Attributes[typeof(DefaultValueAttribute)];
if (myAttribute != null)
{
property.SetValue(this, myAttribute.Value);
}
}
}
public void DoTest()
{
var db = DefaultValueBool;
var ds = DefaultValueString;
var di = DefaultValueInt;
}
[System.ComponentModel.DefaultValue(true)]
public bool DefaultValueBool { get; set; }
[System.ComponentModel.DefaultValue("Good")]
public string DefaultValueString { get; set; }
[System.ComponentModel.DefaultValue(27)]
public int DefaultValueInt { get; set; }
}
When you inline an initial value for a variable it will be done implicitly in the constructor anyway.
I would argue that this syntax was best practice in C# up to 5:
class Person
{
public Person()
{
//do anything before variable assignment
//assign initial values
Name = "Default Name";
//do anything after variable assignment
}
public string Name { get; set; }
}
As this gives you clear control of the order values are assigned.
As of C#6 there is a new way:
public string Name { get; set; } = "Default Name";
Sometimes I use this, if I don't want it to be actually set and persisted in my db:
class Person
{
private string _name;
public string Name
{
get
{
return string.IsNullOrEmpty(_name) ? "Default Name" : _name;
}
set { _name = value; }
}
}
Obviously if it's not a string then I might make the object nullable ( double?, int? ) and check if it's null, return a default, or return the value it's set to.
Then I can make a check in my repository to see if it's my default and not persist, or make a backdoor check in to see the true status of the backing value, before saving.
In C# 6.0 this is a breeze!
You can do it in the Class declaration itself, in the property declaration statements.
public class Coordinate
{
public int X { get; set; } = 34; // get or set auto-property with initializer
public int Y { get; } = 89; // read-only auto-property with initializer
public int Z { get; } // read-only auto-property with no initializer
// so it has to be initialized from constructor
public Coordinate() // .ctor()
{
Z = 42;
}
}
Starting with C# 6.0, We can assign default value to auto-implemented properties.
public string Name { get; set; } = "Some Name";
We can also create read-only auto implemented property like:
public string Name { get; } = "Some Name";
See: C# 6: First reactions , Initializers for automatically implemented properties - By Jon Skeet
In Version of C# (6.0) & greater, you can do :
For Readonly properties
public int ReadOnlyProp => 2;
For both Writable & Readable properties
public string PropTest { get; set; } = "test";
In current Version of C# (7.0), you can do : (The snippet rather displays how you can use expression bodied get/set accessors to make is more compact when using with backing fields)
private string label = "Default Value";
// Expression-bodied get / set accessors.
public string Label
{
get => label;
set => this.label = value;
}
In C# 9.0 was added support of init keyword - very useful and extremly sophisticated way for declaration read-only auto-properties:
Declare:
class Person
{
public string Name { get; init; } = "Anonymous user";
}
~Enjoy~ Use:
// 1. Person with default name
var anonymous = new Person();
Console.WriteLine($"Hello, {anonymous.Name}!");
// > Hello, Anonymous user!
// 2. Person with assigned value
var me = new Person { Name = "#codez0mb1e"};
Console.WriteLine($"Hello, {me.Name}!");
// > Hello, #codez0mb1e!
// 3. Attempt to re-assignment Name
me.Name = "My fake";
// > Compilation error: Init-only property can only be assigned in an object initializer
In addition to the answer already accepted, for the scenario when you want to define a default property as a function of other properties you can use expression body notation on C#6.0 (and higher) for even more elegant and concise constructs like:
public class Person{
public string FullName => $"{First} {Last}"; // expression body notation
public string First { get; set; } = "First";
public string Last { get; set; } = "Last";
}
You can use the above in the following fashion
var p = new Person();
p.FullName; // First Last
p.First = "Jon";
p.Last = "Snow";
p.FullName; // Jon Snow
In order to be able to use the above "=>" notation, the property must be read only, and you do not use the get accessor keyword.
Details on MSDN
In C# 6 and above you can simply use the syntax:
public object Foo { get; set; } = bar;
Note that to have a readonly property simply omit the set, as so:
public object Foo { get; } = bar;
You can also assign readonly auto-properties from the constructor.
Prior to this I responded as below.
I'd avoid adding a default to the constructor; leave that for dynamic assignments and avoid having two points at which the variable is assigned (i.e. the type default and in the constructor). Typically I'd simply write a normal property in such cases.
One other option is to do what ASP.Net does and define defaults via an attribute:
http://msdn.microsoft.com/en-us/library/system.componentmodel.defaultvalueattribute.aspx
My solution is to use a custom attribute that provides default value property initialization by constant or using property type initializer.
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class InstanceAttribute : Attribute
{
public bool IsConstructorCall { get; private set; }
public object[] Values { get; private set; }
public InstanceAttribute() : this(true) { }
public InstanceAttribute(object value) : this(false, value) { }
public InstanceAttribute(bool isConstructorCall, params object[] values)
{
IsConstructorCall = isConstructorCall;
Values = values ?? new object[0];
}
}
To use this attribute it's necessary to inherit a class from special base class-initializer or use a static helper method:
public abstract class DefaultValueInitializer
{
protected DefaultValueInitializer()
{
InitializeDefaultValues(this);
}
public static void InitializeDefaultValues(object obj)
{
var props = from prop in obj.GetType().GetProperties()
let attrs = prop.GetCustomAttributes(typeof(InstanceAttribute), false)
where attrs.Any()
select new { Property = prop, Attr = ((InstanceAttribute)attrs.First()) };
foreach (var pair in props)
{
object value = !pair.Attr.IsConstructorCall && pair.Attr.Values.Length > 0
? pair.Attr.Values[0]
: Activator.CreateInstance(pair.Property.PropertyType, pair.Attr.Values);
pair.Property.SetValue(obj, value, null);
}
}
}
Usage example:
public class Simple : DefaultValueInitializer
{
[Instance("StringValue")]
public string StringValue { get; set; }
[Instance]
public List<string> Items { get; set; }
[Instance(true, 3,4)]
public Point Point { get; set; }
}
public static void Main(string[] args)
{
var obj = new Simple
{
Items = {"Item1"}
};
Console.WriteLine(obj.Items[0]);
Console.WriteLine(obj.Point);
Console.WriteLine(obj.StringValue);
}
Output:
Item1
(X=3,Y=4)
StringValue
little complete sample:
using System.ComponentModel;
private bool bShowGroup ;
[Description("Show the group table"), Category("Sea"),DefaultValue(true)]
public bool ShowGroup
{
get { return bShowGroup; }
set { bShowGroup = value; }
}
You can simple put like this
public sealed class Employee
{
public int Id { get; set; } = 101;
}
In the constructor. The constructor's purpose is to initialized it's data members.
private string name;
public string Name
{
get
{
if(name == null)
{
name = "Default Name";
}
return name;
}
set
{
name = value;
}
}
Have you tried using the DefaultValueAttribute or ShouldSerialize and Reset methods in conjunction with the constructor? I feel like one of these two methods is necessary if you're making a class that might show up on the designer surface or in a property grid.
Use the constructor because "When the constructor is finished, Construction should be finished". properties are like states your classes hold, if you had to initialize a default state, you would do that in your constructor.
To clarify, yes, you need to set default values in the constructor for class derived objects. You will need to ensure the constructor exists with the proper access modifier for construction where used. If the object is not instantiated, e.g. it has no constructor (e.g. static methods) then the default value can be set by the field. The reasoning here is that the object itself will be created only once and you do not instantiate it.
#Darren Kopp - good answer, clean, and correct. And to reiterate, you CAN write constructors for Abstract methods. You just need to access them from the base class when writing the constructor:
Constructor at Base Class:
public BaseClassAbstract()
{
this.PropertyName = "Default Name";
}
Constructor at Derived / Concrete / Sub-Class:
public SubClass() : base() { }
The point here is that the instance variable drawn from the base class may bury your base field name. Setting the current instantiated object value using "this." will allow you to correctly form your object with respect to the current instance and required permission levels (access modifiers) where you are instantiating it.
public Class ClassName{
public int PropName{get;set;}
public ClassName{
PropName=0; //Default Value
}
}
This is old now, and my position has changed. I'm leaving the original answer for posterity only.
Personally, I don't see the point of making it a property at all if you're not going to do anything at all beyond the auto-property. Just leave it as a field. The encapsulation benefit for these item are just red herrings, because there's nothing behind them to encapsulate. If you ever need to change the underlying implementation you're still free to refactor them as properties without breaking any dependent code.
Hmm... maybe this will be the subject of it's own question later
class Person
{
/// Gets/sets a value indicating whether auto
/// save of review layer is enabled or not
[System.ComponentModel.DefaultValue(true)]
public bool AutoSaveReviewLayer { get; set; }
}
I know this is an old question, but it came up when I was looking for how to have a default value that gets inherited with the option to override, I came up with
//base class
public class Car
{
public virtual string FuelUnits
{
get { return "gasoline in gallons"; }
protected set { }
}
}
//derived
public class Tesla : Car
{
public override string FuelUnits => "ampere hour";
}
I think this would do it for ya givng SomeFlag a default of false.
private bool _SomeFlagSet = false;
public bool SomeFlag
{
get
{
if (!_SomeFlagSet)
SomeFlag = false;
return SomeFlag;
}
set
{
if (!_SomeFlagSet)
_SomeFlagSet = true;
SomeFlag = value;
}
}
How do you give a C# auto-property an initial value?
I either use the constructor, or revert to the old syntax.
Using the Constructor:
class Person
{
public Person()
{
Name = "Initial Name";
}
public string Name { get; set; }
}
Using normal property syntax (with an initial value)
private string name = "Initial Name";
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
Is there a better way?
In C# 5 and earlier, to give auto implemented properties an initial value, you have to do it in a constructor.
Since C# 6.0, you can specify initial value in-line. The syntax is:
public int X { get; set; } = x; // C# 6 or higher
DefaultValueAttribute is intended to be used by the VS designer (or any other consumer) to specify a default value, not an initial value. (Even if in designed object, initial value is the default value).
At compile time DefaultValueAttribute will not impact the generated IL and it will not be read to initialize the property to that value (see DefaultValue attribute is not working with my Auto Property).
Example of attributes that impact the IL are ThreadStaticAttribute, CallerMemberNameAttribute, ...
Edited on 1/2/15
C# 6 :
With C# 6 you can initialize auto-properties directly (finally!), there are now other answers that describe that.
C# 5 and below:
Though the intended use of the attribute is not to actually set the values of the properties, you can use reflection to always set them anyway...
public class DefaultValuesTest
{
public DefaultValuesTest()
{
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(this))
{
DefaultValueAttribute myAttribute = (DefaultValueAttribute)property.Attributes[typeof(DefaultValueAttribute)];
if (myAttribute != null)
{
property.SetValue(this, myAttribute.Value);
}
}
}
public void DoTest()
{
var db = DefaultValueBool;
var ds = DefaultValueString;
var di = DefaultValueInt;
}
[System.ComponentModel.DefaultValue(true)]
public bool DefaultValueBool { get; set; }
[System.ComponentModel.DefaultValue("Good")]
public string DefaultValueString { get; set; }
[System.ComponentModel.DefaultValue(27)]
public int DefaultValueInt { get; set; }
}
When you inline an initial value for a variable it will be done implicitly in the constructor anyway.
I would argue that this syntax was best practice in C# up to 5:
class Person
{
public Person()
{
//do anything before variable assignment
//assign initial values
Name = "Default Name";
//do anything after variable assignment
}
public string Name { get; set; }
}
As this gives you clear control of the order values are assigned.
As of C#6 there is a new way:
public string Name { get; set; } = "Default Name";
Sometimes I use this, if I don't want it to be actually set and persisted in my db:
class Person
{
private string _name;
public string Name
{
get
{
return string.IsNullOrEmpty(_name) ? "Default Name" : _name;
}
set { _name = value; }
}
}
Obviously if it's not a string then I might make the object nullable ( double?, int? ) and check if it's null, return a default, or return the value it's set to.
Then I can make a check in my repository to see if it's my default and not persist, or make a backdoor check in to see the true status of the backing value, before saving.
In C# 6.0 this is a breeze!
You can do it in the Class declaration itself, in the property declaration statements.
public class Coordinate
{
public int X { get; set; } = 34; // get or set auto-property with initializer
public int Y { get; } = 89; // read-only auto-property with initializer
public int Z { get; } // read-only auto-property with no initializer
// so it has to be initialized from constructor
public Coordinate() // .ctor()
{
Z = 42;
}
}
Starting with C# 6.0, We can assign default value to auto-implemented properties.
public string Name { get; set; } = "Some Name";
We can also create read-only auto implemented property like:
public string Name { get; } = "Some Name";
See: C# 6: First reactions , Initializers for automatically implemented properties - By Jon Skeet
In Version of C# (6.0) & greater, you can do :
For Readonly properties
public int ReadOnlyProp => 2;
For both Writable & Readable properties
public string PropTest { get; set; } = "test";
In current Version of C# (7.0), you can do : (The snippet rather displays how you can use expression bodied get/set accessors to make is more compact when using with backing fields)
private string label = "Default Value";
// Expression-bodied get / set accessors.
public string Label
{
get => label;
set => this.label = value;
}
In C# 9.0 was added support of init keyword - very useful and extremly sophisticated way for declaration read-only auto-properties:
Declare:
class Person
{
public string Name { get; init; } = "Anonymous user";
}
~Enjoy~ Use:
// 1. Person with default name
var anonymous = new Person();
Console.WriteLine($"Hello, {anonymous.Name}!");
// > Hello, Anonymous user!
// 2. Person with assigned value
var me = new Person { Name = "#codez0mb1e"};
Console.WriteLine($"Hello, {me.Name}!");
// > Hello, #codez0mb1e!
// 3. Attempt to re-assignment Name
me.Name = "My fake";
// > Compilation error: Init-only property can only be assigned in an object initializer
In addition to the answer already accepted, for the scenario when you want to define a default property as a function of other properties you can use expression body notation on C#6.0 (and higher) for even more elegant and concise constructs like:
public class Person{
public string FullName => $"{First} {Last}"; // expression body notation
public string First { get; set; } = "First";
public string Last { get; set; } = "Last";
}
You can use the above in the following fashion
var p = new Person();
p.FullName; // First Last
p.First = "Jon";
p.Last = "Snow";
p.FullName; // Jon Snow
In order to be able to use the above "=>" notation, the property must be read only, and you do not use the get accessor keyword.
Details on MSDN
In C# 6 and above you can simply use the syntax:
public object Foo { get; set; } = bar;
Note that to have a readonly property simply omit the set, as so:
public object Foo { get; } = bar;
You can also assign readonly auto-properties from the constructor.
Prior to this I responded as below.
I'd avoid adding a default to the constructor; leave that for dynamic assignments and avoid having two points at which the variable is assigned (i.e. the type default and in the constructor). Typically I'd simply write a normal property in such cases.
One other option is to do what ASP.Net does and define defaults via an attribute:
http://msdn.microsoft.com/en-us/library/system.componentmodel.defaultvalueattribute.aspx
My solution is to use a custom attribute that provides default value property initialization by constant or using property type initializer.
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class InstanceAttribute : Attribute
{
public bool IsConstructorCall { get; private set; }
public object[] Values { get; private set; }
public InstanceAttribute() : this(true) { }
public InstanceAttribute(object value) : this(false, value) { }
public InstanceAttribute(bool isConstructorCall, params object[] values)
{
IsConstructorCall = isConstructorCall;
Values = values ?? new object[0];
}
}
To use this attribute it's necessary to inherit a class from special base class-initializer or use a static helper method:
public abstract class DefaultValueInitializer
{
protected DefaultValueInitializer()
{
InitializeDefaultValues(this);
}
public static void InitializeDefaultValues(object obj)
{
var props = from prop in obj.GetType().GetProperties()
let attrs = prop.GetCustomAttributes(typeof(InstanceAttribute), false)
where attrs.Any()
select new { Property = prop, Attr = ((InstanceAttribute)attrs.First()) };
foreach (var pair in props)
{
object value = !pair.Attr.IsConstructorCall && pair.Attr.Values.Length > 0
? pair.Attr.Values[0]
: Activator.CreateInstance(pair.Property.PropertyType, pair.Attr.Values);
pair.Property.SetValue(obj, value, null);
}
}
}
Usage example:
public class Simple : DefaultValueInitializer
{
[Instance("StringValue")]
public string StringValue { get; set; }
[Instance]
public List<string> Items { get; set; }
[Instance(true, 3,4)]
public Point Point { get; set; }
}
public static void Main(string[] args)
{
var obj = new Simple
{
Items = {"Item1"}
};
Console.WriteLine(obj.Items[0]);
Console.WriteLine(obj.Point);
Console.WriteLine(obj.StringValue);
}
Output:
Item1
(X=3,Y=4)
StringValue
little complete sample:
using System.ComponentModel;
private bool bShowGroup ;
[Description("Show the group table"), Category("Sea"),DefaultValue(true)]
public bool ShowGroup
{
get { return bShowGroup; }
set { bShowGroup = value; }
}
You can simple put like this
public sealed class Employee
{
public int Id { get; set; } = 101;
}
In the constructor. The constructor's purpose is to initialized it's data members.
private string name;
public string Name
{
get
{
if(name == null)
{
name = "Default Name";
}
return name;
}
set
{
name = value;
}
}
Have you tried using the DefaultValueAttribute or ShouldSerialize and Reset methods in conjunction with the constructor? I feel like one of these two methods is necessary if you're making a class that might show up on the designer surface or in a property grid.
Use the constructor because "When the constructor is finished, Construction should be finished". properties are like states your classes hold, if you had to initialize a default state, you would do that in your constructor.
To clarify, yes, you need to set default values in the constructor for class derived objects. You will need to ensure the constructor exists with the proper access modifier for construction where used. If the object is not instantiated, e.g. it has no constructor (e.g. static methods) then the default value can be set by the field. The reasoning here is that the object itself will be created only once and you do not instantiate it.
#Darren Kopp - good answer, clean, and correct. And to reiterate, you CAN write constructors for Abstract methods. You just need to access them from the base class when writing the constructor:
Constructor at Base Class:
public BaseClassAbstract()
{
this.PropertyName = "Default Name";
}
Constructor at Derived / Concrete / Sub-Class:
public SubClass() : base() { }
The point here is that the instance variable drawn from the base class may bury your base field name. Setting the current instantiated object value using "this." will allow you to correctly form your object with respect to the current instance and required permission levels (access modifiers) where you are instantiating it.
public Class ClassName{
public int PropName{get;set;}
public ClassName{
PropName=0; //Default Value
}
}
This is old now, and my position has changed. I'm leaving the original answer for posterity only.
Personally, I don't see the point of making it a property at all if you're not going to do anything at all beyond the auto-property. Just leave it as a field. The encapsulation benefit for these item are just red herrings, because there's nothing behind them to encapsulate. If you ever need to change the underlying implementation you're still free to refactor them as properties without breaking any dependent code.
Hmm... maybe this will be the subject of it's own question later
class Person
{
/// Gets/sets a value indicating whether auto
/// save of review layer is enabled or not
[System.ComponentModel.DefaultValue(true)]
public bool AutoSaveReviewLayer { get; set; }
}
I know this is an old question, but it came up when I was looking for how to have a default value that gets inherited with the option to override, I came up with
//base class
public class Car
{
public virtual string FuelUnits
{
get { return "gasoline in gallons"; }
protected set { }
}
}
//derived
public class Tesla : Car
{
public override string FuelUnits => "ampere hour";
}
I think this would do it for ya givng SomeFlag a default of false.
private bool _SomeFlagSet = false;
public bool SomeFlag
{
get
{
if (!_SomeFlagSet)
SomeFlag = false;
return SomeFlag;
}
set
{
if (!_SomeFlagSet)
_SomeFlagSet = true;
SomeFlag = value;
}
}
Can somebody help me understand the get & set?
Why are they needed? I can just make a public variable.
Warning: I am assuming you already know about object-oriented programming.
What are properties?
Properties are language elements that allow you to avoid the repetitive getXYZ() accessors and setXYZ() mutators techniques found in other languages, like Java.
Why do they exist?
They aim to solve the following problems:
Saying get and set in the beginning of every access or mutation of a value is annoying and distracting.
In Java, you often say:
class person
{
private int _age;
public void setAge(int value) { /*check value first, then set _age*/ }
public int getAge() { return this._age; }
}
and then consistently say:
if (person.getAge() > blah || person.getAge() < 10)
{
person.setAge(5);
}
After a while, the get and set become rather annoying.
Providing direct access to the actual variable breaks encapsulation, so that's not an option.
How are they used?
They are used just like variables. You read/write to them just like variables.
How are they created?
They are created as methods. You define a pair of methods that:
Return the current value of the property. Oftentimes, this is nothing more than something like the following:
class Person
{
private int _age; //Declare the backing field
public int Age
{
get { return this._age; }
set { ... }
}
}
Set the value of the property:
class Person
{
public int Age
{
get { ... }
set
{
if (value < 0) //'value' is what the user provided
{ throw new ArgumentOutOfRangeException(); } //Check validity
this._age = value;
}
}
}
Other notes:
Auto-implemented Properties
C# 3.0 introduced auto-implemented properties:
public int Age { get; set; }
This is equivalent to:
private int _age; //The name is auto-generated
public int Age { get { return this._age; } set { this._age = value; } }
Why does it exist?
It helps you avoiding breaking changes in client executables.
Let's say you're lazy and don't want to type the whole thing, and decide to expose a variable publicly. You then create an executable that reads from or writes to that field. Then you change your mind and decide that you in fact needed a property, so you change it to one.
What happens?
The depending executable breaks, because the code is no longer valid.
Auto-implemented properties help you avoid that, without extra redundancy in your initial code.
Indexers
Indexers extend the property syntax to let you index objects (surprise!), just like arrays.
For C++ users: This is similar to overloading operator [].
Example:
private int[] _elements;
public int this[int index] //Indexed property
{
get { return this._elements[index]; }
set
{
//Do any checks on the index and value
this._elements[index] = value;
}
}
You then use them like obj[5] = 10;, which is equivalent to calling the set method of obj's indexer.
In fact, System.Collections.Generic.List<T> is indexed:
var list = new List<int>();
list.Add(10);
list[0] = 5; //You're indexing list, as though it were an array!
Isn't that neat? :)
Anything else?
There are many more features to properties, not all of which are available in C#:
Parametrized properties, of which indexers are a special kind
Getter/setter access modifiers (in C#)
Multiple getters or setters (not in C#)
Et cetera
They are called Accessors
The accessor of a property contains the executable statements associated with getting (reading or computing) or setting (writing) the property. The accessor declarations can contain a get accessor, a set accessor, or both.
The body of the get accessor resembles that of a method. It must return a value of the property type.
http://msdn.microsoft.com/en-us/library/w86s7x04.aspx
private string m_Name; // the name field
public string Name // the Name property
{
get
{
return m_Name;
}
}
The set accessor resembles a method whose return type is void. It uses an implicit parameter called value, whose type is the type of the property.
private m_Name;
public string Name {
get {
return m_Name;
}
set {
m_Name = value;
}
}
Then in the incarnation of C# 3, you can do this much easier through auto-properties
public string Name {get; set; } // read and write
public string Name {get; } // read only
public string Name { get; private set; } //read and parent write
http://msdn.microsoft.com/en-us/library/bb384054.aspx
Properties act as accessors to the internal state of an object, hiding the implementation of that state.
So, for example, you may have a first name property in a class
public class Example
{
private string firstName;
public string FirstName
{
get {return this.firstName;}
}
}
So anyone using the class doesn't need to know how first name is stored, they just know they can get a string representation of it. By adding a set you also add a mutator, something which changes an objects internal state
public class Example
{
private string firstName;
public string FirstName
{
get {return this.firstName;}
set {set this.firstName = value;}
}
}
Again you're still isolating how the first name is stored internally (encapsulation), but users can change it by passing in a string.
Simply put, get and set accessors are the functions called on a Property; that is, when you retrieve the value or when you set it. It forces a type of behavior on the way values are retrieved or set.
For example, you may want to have a mechanism to get/set passwords. Generally speaking, you'll only want to compare the hash of a password instead of storing things plaintext, so you'd have the getter variable retrieve the stored hash, and the setter would take the provided input and hash it for storage.
Here's what I mean:
public class User {
//Usery properties here, and...
private string _password;
public string Password {
get {
return _password;
}
set {
_password = SomeHashingFunction(value);
}
}
}
value is the variable provided to the setter from what has been given in the variable assignment. e.g.: someuser.Password = "blah";
Get and set are used in properties. They can each be public, protected, or private. Similar to accessor and mutator methods, they allow some computation when code tries to access/mutate the property. Of course, as long as you define one of get/set, the other is optional.
Example without properties:
private int test;
public int getTest() {
// some computation on test here, maybe?
return test;
}
private void setTest(int test) {
// some error/range checking, maybe?
this.test = test;
}
With properties:
private int test;
public int Test {
get {
// some computation on test here, maybe?
return test;
}
private set {
// some error/range checking, maybe?
test = value; // value is a keyword here
}
}
get{} and set{} are accessors that offer up the ability to easily read and write to private fields. Working with a simple example:
public class Foo()
{
//Field
private int _bar;
//Property
public int Bar
{
get { return _bar; }
set { _bar = value; }
//value is an implicit parameter to the set acccessor.
//When you perform an assignment to the property, the value you
//assign is the value in "value"
}
}
In this case, Bar is a public property that has a getter and a setter that allows access to the private field _bar that would otherwise be inaccessible beyond class Foo.
Now in a class that has an instace of Foo, you can do this:
public class IHasAFoo()
{
private Foo _myFoo = new Foo();
public void SomeMethod()
{
_myFoo.Bar = 42;
}
}
So the public accessor allows you to set the value of the private field back in Foo.
Hope that helps!
Suppose I have:
public class Bob
{
public int Value { get; set; }
}
I want to pass the Value member as an out parameter like
Int32.TryParse("123", out bob.Value);
but I get a compilation error, "'out' argument is not classified as a variable." Is there any way to achieve this, or am I going to have to extract a variable, à la:
int value;
Int32.TryParse("123", out value);
bob.Value = value;
You'd have to explicitly use a field and "normal" property instead of an auto-implemented property:
public class Bob
{
private int value;
public int Value
{
get { return value; }
set { this.value = value; }
}
}
Then you can pass the field as an out parameter:
Int32.TryParse("123", out bob.value);
But of course, that will only work within the same class, as the field is private (and should be!).
Properties just don't let you do this. Even in VB where you can pass a property by reference or use it as an out parameter, there's basically an extra temporary variable.
If you didn't care about the return value of TryParse, you could always write your own helper method:
static int ParseOrDefault(string text)
{
int tmp;
int.TryParse(text, out tmp);
return tmp;
}
Then use:
bob.Value = Int32Helper.ParseOrDefault("123");
That way you can use a single temporary variable even if you need to do this in multiple places.
You can achieve that, but not with a property.
public class Bob {
public int Value { get; set; } // This is a property
public int AnotherValue; // This is a field
}
You cannot use out on Value, but you can on AnotherValue.
This will work
Int32.TryParse("123", out bob.AnotherValue);
But, common guidelines tells you not to make a class field public. So you should use the temporary variable approach.