C# classes can declare indexers to provide array-like access to the classes.
For example, suppose you want to define a class that makes a file appear as an array of bytes. If the file were very large, it would be impractical to read the entire file into memory, especially if you only wanted to read or change a few bytes. By defining a FileByteArray
class, you could make the file appear similar to an array of bytes, but actually do file input and output when a byte was read or written.
using System; using System.IO; // Class to provide access to a large file // as if it were a byte array. public class FileByteArray { Stream stream; // Holds the underlying stream // used to access the file. // Create a new FileByteArray encapsulating a particular file. public FileByteArray(string fileName) { stream = new FileStream(fileName, FileMode.Open); } // Close the stream. This should be the last thing done // when you are finished. public void Close() { stream.Close(); stream = null; } // Indexer to provide read/write access to the file. public byte this[long index] // long is a 64-bit integer { // Read one byte at offset index and return it. get { byte[] buffer = new byte[1]; stream.Seek(index, SeekOrigin.Begin); stream.Read(buffer, 0, 1); return buffer[0]; } // Write one byte at offset index and return it. set { byte[] buffer = new byte[1] {value}; stream.Seek(index, SeekOrigin.Begin); stream.Write(buffer, 0, 1); } } // Get the total length of the file. public long Length { get { return stream.Seek(0, SeekOrigin.End); } } } // Demonstrate the FileByteArray class. // Reverses the bytes in a file. public class Reverse { public static void Main(String[] args) { // Check for arguments. if (args.Length == 0) { Console.WriteLine("indexer <filename>"); return; } FileByteArray file = new FileByteArray(args[0]); long len = file.Length; // Swap bytes in the file to reverse it. for (long i = 0; i < len / 2; ++i) { byte t; // Note that indexing the "file" variable invokes the // indexer on the FileByteStream class, which reads // and writes the bytes in the file. t = file[i]; file[i] = file[len - i - 1]; file[len - i - 1] = t; } file.Close(); } }
Index property sample
using System; public class Document { // Type allowing the document to be viewed like an array of words: public class WordCollection { readonly Document document; // The containing document internal WordCollection(Document d) { document = d; } // Helper function -- search character array "text", starting at // character "begin", for word number "wordCount." Returns false // if there are less than wordCount words. Sets "start" and // length" to the position and length of the word within text: private bool GetWord(char[] text, int begin, int wordCount, out int start, out int length) { int end = text.Length; int count = 0; int inWord = -1; start = length = 0; for (int i = begin; i <= end; ++i) { bool isLetter = i < end && Char.IsLetterOrDigit(text[i]); if (inWord >= 0) { if (!isLetter) { if (count++ == wordCount) { start = inWord; length = i - inWord; return true; } inWord = -1; } } else { if (isLetter) inWord = i; } } return false; } // Indexer to get and set words of the containing document: public string this[int index] { get { int start, length; if (GetWord(document.TextArray, 0, index, out start, out length)) return new string(document.TextArray, start, length); else throw new IndexOutOfRangeException(); } set { int start, length; if (GetWord(document.TextArray, 0, index, out start, out length)) { // Replace the word at start/length with the // string "value": if (length == value.Length) { Array.Copy(value.ToCharArray(), 0, document.TextArray, start, length); } else { char[] newText = new char[document.TextArray.Length + value.Length - length]; Array.Copy(document.TextArray, 0, newText, 0, start); Array.Copy(value.ToCharArray(), 0, newText, start, value.Length); Array.Copy(document.TextArray, start + length, newText, start + value.Length, document.TextArray.Length - start - length); document.TextArray = newText; } } else throw new IndexOutOfRangeException(); } } // Get the count of words in the containing document: public int Count { get { int count = 0, start = 0, length = 0; while (GetWord(document.TextArray, start + length, 0, out start, out length)) ++count; return count; } } } // Type allowing the document to be viewed like an "array" // of characters: public class CharacterCollection { readonly Document document; // The containing document internal CharacterCollection(Document d) { document = d; } // Indexer to get and set characters in the containing document: public char this[int index] { get { return document.TextArray[index]; } set { document.TextArray[index] = value; } } // Get the count of characters in the containing document: public int Count { get { return document.TextArray.Length; } } } // Because the types of the fields have indexers, // these fields appear as "indexed properties": public readonly WordCollection Words; public readonly CharacterCollection Characters; private char[] TextArray; // The text of the document. public Document(string initialText) { TextArray = initialText.ToCharArray(); Words = new WordCollection(this); Characters = new CharacterCollection(this); } public string Text { get { return new string(TextArray); } } } class Test { static void Main() { Document d = new Document( "peter piper picked a peck of pickled peppers. How many pickled peppers did peter piper pick?" ); // Change word "peter" to "penelope": for (int i = 0; i < d.Words.Count; ++i) { if (d.Words[i] == "peter") d.Words[i] = "penelope"; } // Change character "p" to "P" for (int i = 0; i < d.Characters.Count; ++i) { if (d.Characters[i] == 'p') d.Characters[i] = 'P'; } Console.WriteLine(d.Text); } }