| 1 | = Properties = |
| 2 | Properties are members that are used as if they are public data members, but are actually implemented via special methods called accessors.[[BR]] |
| 3 | They are accessed using the same syntax as fields but do not designate storage locations.[[BR]] |
| 4 | Instead, properties have accessors that read, write, or compute their values.[[BR]] |
| 5 | Values can be reflected directly (or indirectly (filtered)) in or out of a backing variable or computed, Its entirely up to the accessor. |
| 6 | |
| 7 | There are 3 keywords for defining a property:[[BR]] |
| 8 | '''get''' defines a readOnly property ( Can access its value but cant change it). [[BR]] |
| 9 | '''set''' defines a writeOnly property ( Can write a new value but cant read it).[[BR]] |
| 10 | '''pro''' defines a property that is both readable and writable. |
| 11 | |
| 12 | Most commonly a property accessor uses a backing variable (field) which the accessor just reflects.[[BR]] |
| 13 | There is a special form to simplify this using a clause beginning with keyword '''from'''. |
| 14 | * '''from var''' [[BR]] |
| 15 | If the word following '''from''' is '''var''' the property will get or set its value unchanged [[BR]] |
| 16 | from a backing variable named the same as the property name with a single underscore prepended to it. |
| 17 | * If the backing variable doesn't exist but there is an initial value assignment to the property or [[BR]] |
| 18 | a type declaration on the property, the backing variable will be implicitly created for you |
| 19 | * '''from <backingVarId>'''[[BR]] |
| 20 | Otherwise the word following the '''from''' must be the name of an existing backing store variable. |
| 21 | |
| 22 | {{{ |
| 23 | var _nLife = 47 # protected access |
| 24 | pro nLife from var # property nLife uses backing var _nLife |
| 25 | # above same as |
| 26 | pro nLife from _nLife |
| 27 | # but can use a different backing variable name from property name |
| 28 | pro numLife from _nLife |
| 29 | |
| 30 | # or use a backing variable with different (shortcutted) accessability |
| 31 | var __nLife0 = 48 # private access |
| 32 | |
| 33 | pro nLife from __nLife |
| 34 | }}} |
| 35 | |
| 36 | Can implicitly create initialised backing variable and property in one line like |
| 37 | {{{ |
| 38 | pro nLife = 47 |
| 39 | }}} |
| 40 | |
| 41 | Finally if an accessor needs to translate, filter or modify in some way a backing variable or provide a virtual variable (computed)[[BR]] |
| 42 | there is a longer syntax variant where either of both the '''get''' and '''set''' accessors can be specified with a block of code to[[BR]] |
| 43 | store (setter) or generate (getter) the property value. |
| 44 | |
| 45 | Properties can have Attributes and the default [wiki:accessModifiers access modifiers] can be overridden explicitly if desired. |
| 46 | |
| 47 | !DocStrings describing the property are both allowed and encouraged. |
| 48 | |
| 49 | There is a special type of property called an Indexor which allows an instance to be accessed[[BR]] |
| 50 | using an array offset like syntax {{{ e.g. coll[x] }}}. [[BR]] |
| 51 | Usually this is implemented for classes that act as containers, for access to the contained items.[[BR]] |
| 52 | The syntax for indexors is as described above except that the property name is '''[]''' with indexes comma [[BR]] |
| 53 | separated (if multiple) between the [] and the accessors must be coded explicitly ( the '''from''' clause shorthand is not available). |
| 54 | |
| 55 | == Grammar == |
| 56 | |
| 57 | {{{ |
| 58 | get <propName> [as <Type>] [from {var, <backingVariableName>} [= <initValue>] ] |
| 59 | [has <AttributeList>] |
| 60 | [is <accessModifier>] |
| 61 | [<DocString>] |
| 62 | |
| 63 | set <propName> [as <Type>] [from {var, <backingVariableName>} [= <initValue>] ] |
| 64 | [has <AttributeList>] |
| 65 | [is <accessModifier>] |
| 66 | [<DocString>] |
| 67 | |
| 68 | pro <propName> [as <Type>] [from {var, <backingVariableName>} [= <initValue>]] |
| 69 | [has <AttributeList>] |
| 70 | [is <accessModifier>] |
| 71 | [<DocString>] |
| 72 | |
| 73 | # full accessor variant |
| 74 | pro <propName> |
| 75 | [has <AttributeList>] |
| 76 | [is <accessModifier>] |
| 77 | [<DocString>] |
| 78 | |
| 79 | get |
| 80 | [...] |
| 81 | return <value> |
| 82 | set |
| 83 | [...] # assign or otherwise do something with implicit arg "value" (passed in) |
| 84 | |
| 85 | #Indexors |
| 86 | |
| 87 | {pro,set,get} '[' <indexer expression> ']' [as <Type>] |
| 88 | [has <AttributeList>] |
| 89 | [is <accessModifier>] |
| 90 | [<DocString>] |
| 91 | [ |
| 92 | get |
| 93 | [...] |
| 94 | return <value> |
| 95 | set |
| 96 | [...] # assign or otherwise do something with implicit arg "value" (passed in) |
| 97 | }}} |
| 98 | |
| 99 | == Examples == |
| 100 | {{{ |
| 101 | class TimePeriod |
| 102 | var seconds as float32 is private |
| 103 | |
| 104 | pro hours as float32 |
| 105 | get |
| 106 | return .seconds / 3600 |
| 107 | set |
| 108 | .seconds = value * 3600 |
| 109 | |
| 110 | class Program |
| 111 | def main is shared |
| 112 | t = TimePeriod() |
| 113 | |
| 114 | # Assigning the hours property causes the 'set' accessor to be called. |
| 115 | t.hours = 24 |
| 116 | |
| 117 | # Evaluating the hours property causes the 'get' accessor to be called. |
| 118 | print "Time in hours: ", t.hours |
| 119 | }}} |
| 120 | |
| 121 | |
| 122 | |
| 123 | {{{ |
| 124 | class Employee |
| 125 | var numberOfEmployees as int = 0 |
| 126 | is shared |
| 127 | var __counter as int = 0 |
| 128 | is shared |
| 129 | var _name = '' |
| 130 | |
| 131 | # A read-write instance property: |
| 132 | pro name from var |
| 133 | |
| 134 | # A read-only static property: |
| 135 | get counter from __counter is shared |
| 136 | |
| 137 | # Constructor: |
| 138 | cue init |
| 139 | base.init |
| 140 | # Calculate the employee's number: |
| 141 | __counter = .counter + 1 + .numberOfEmployees |
| 142 | |
| 143 | class MainClass |
| 144 | def main is shared |
| 145 | Employee.numberOfEmployees = 100 |
| 146 | e1 = Employee() |
| 147 | e1.name = "Claude Vige" |
| 148 | print String.format("Employee number: {0}", Employee.counter) |
| 149 | print String.format("Employee name: {0}", e1.name) |
| 150 | # Output is |
| 151 | #Employee number: 101 |
| 152 | #Employee name: Claude Vige |
| 153 | }}} |
| 154 | |
| 155 | |
| 156 | Indexor example |
| 157 | {{{ |
| 158 | class IdxColl |
| 159 | var _coll = [] |
| 160 | |
| 161 | cue init |
| 162 | base.init |
| 163 | _coll = [1,2,3,'xx'] |
| 164 | |
| 165 | pro [idx as int] as Object |
| 166 | get |
| 167 | return _coll[idx] |
| 168 | set |
| 169 | _coll[idx] = value |
| 170 | |
| 171 | def main is shared |
| 172 | c = ProColl() |
| 173 | assert c[0] == 1 |
| 174 | assert c[3] == 'xx' |
| 175 | c[2] = 'yy' |
| 176 | assert c[2] == 'yy' |
| 177 | }}} |
| 178 | |
| 179 | |
| 180 | == Notes == |
| 181 | |
| 182 | |
| 183 | == See Also == |
| 184 | |
| 185 | [http://msdn.microsoft.com/en-us/library/w86s7x04%28VS.71%29.aspx Properties(C# Programming Reference)] |
| 186 | |
| 187 | [http://msdn.microsoft.com/en-us/library/x9fsa0sw.aspx Properties(C# Programming Guide)] |
| 188 | |
| 189 | [wiki:LanguageTopics Back to LanguageTopics] |
| 190 | |
| 191 | |
| 192 | |