Indexed Properties
When defining a class that abstracts over ordered data, it can sometimes be helpful to provide indexed access to that data without exposing the underlying implementation. This is done with the Item
member.
Syntax
Syntax for expressions:
// Looking up an indexed property
expr[idx]
/// Assign to an indexed property
expr[idx] <- elementExpr
Syntax for member declarations:
// Indexed property that can be read and written to
member self-identifier.Item
with get(index-values) =
get-member-body
and set index-values values-to-set =
set-member-body
// Indexed property can only be read
member self-identifier.Item
with get(index-values) =
get-member-body
// Indexed property that can only be set
member self-identifier.Item
with set index-values values-to-set =
set-member-body
Remarks
The forms of the previous syntax show how to define indexed properties that have both a get
and a set
method, have a get
method only, or have a set
method only. You can also combine both the syntax shown for get only and the syntax shown for set only, and produce a property that has both get and set. This latter form allows you to put different accessibility modifiers and attributes on the get and set methods.
By using the name Item
, the compiler treats the property as a default indexed property. A default indexed property is a property that you can access by using array-like syntax on the object instance. For example, if o
is an object of the type that defines this property, the syntax o[index]
is used to access the property.
The syntax for accessing a non-default indexed property is to provide the name of the property and the index in parentheses, just like a regular member. For example, if the property on o
is called Ordinal
, you write o.Ordinal(index)
to access it.
Regardless of which form you use, you should always use the curried form for the set method on an indexed property. For information about curried functions, see Functions.
Prior to F# 6, the syntax expr.[idx]
was used for indexing. You can activate an optional informational warning (/warnon:3366
or property <WarnOn>3366</WarnOn>
) to report uses of the expr.[idx]
notation.
Example
The following code example illustrates the definition and use of default and non-default indexed properties that have get and set methods.
type NumberStrings() =
let mutable ordinals =
[| "one"
"two"
"three"
"four"
"five"
"six"
"seven"
"eight"
"nine"
"ten" |]
let mutable cardinals =
[| "first"
"second"
"third"
"fourth"
"fifth"
"sixth"
"seventh"
"eighth"
"ninth"
"tenth" |]
member this.Item
with get (index) = ordinals[index]
and set index value = ordinals[index] <- value
member this.Ordinal
with get (index) = ordinals[index]
and set index value = ordinals[index] <- value
member this.Cardinal
with get (index) = cardinals[index]
and set index value = cardinals[index] <- value
let nstrs = new NumberStrings()
nstrs[0] <- "ONE"
for i in 0..9 do
printf "%s " nstrs[i]
printfn ""
nstrs.Cardinal(5) <- "6th"
for i in 0..9 do
printf "%s " (nstrs.Ordinal(i))
printf "%s " (nstrs.Cardinal(i))
printfn ""
Output
ONE two three four five six seven eight nine ten
ONE first two second three third four fourth five fifth six 6th
seven seventh eight eighth nine ninth ten tenth
Indexed Properties with multiple index values
Indexed properties can have more than one index value. In that case, the values are separated by commas when the property is used. The set method in such a property must have two curried arguments, the first of which is a tuple containing the keys, and the second of which is the value to set.
The following code demonstrates the use of an indexed property with multiple index values.
open System.Collections.Generic
/// Basic implementation of a sparse matrix based on a dictionary
type SparseMatrix() =
let table = new Dictionary<(int * int), float>()
member _.Item
// Because the key is comprised of two values, 'get' has two index values
with get(key1, key2) = table[(key1, key2)]
// 'set' has two index values and a new value to place in the key's position
and set (key1, key2) value = table[(key1, key2)] <- value
let sm = new SparseMatrix()
for i in 1..1000 do
sm[i, i] <- float i * float i