并不決定INDEXER好用(內(nèi)付INDEXER的圖文說明教程 中文版) :)
發(fā)表時間:2024-06-16 來源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]這一課講述如何在C#的類中聲明索引,以使類能象數(shù)組一樣被訪問,這樣類的實例就能夠使用數(shù)組訪問操作符[]來訪問類對象.在C#中定義索引和在C++中定義操作符[]類似.對于那些封裝了數(shù)組或者使用起來有點象集合的類,就可以使用索引,這樣用戶就能夠使用訪問數(shù)組的語法訪問這個類.舉個例子,假定,你想要定義一...
這一課講述如何在C#的類中聲明索引,以使類能象數(shù)組一樣被訪問,這樣類的實例就能夠使用
數(shù)組訪問操作符[]來訪問類對象.
在C#中定義索引和在C++中定義操作符[]類似.對于那些封裝了數(shù)組或者使用起來有點象集合
的類,就可以使用索引,這樣用戶就能夠使用訪問數(shù)組的語法訪問這個類.
舉個例子,假定,你想要定義一個類,它使得文件就像一個字節(jié)數(shù)組一樣.如果文件非常大,把
整個文件都讀入內(nèi)存是不切合實際的,尤其是在你只想讀寫其中一小部分字節(jié)的時候更是如
此.這里定義了一個類FileByteArray,使文件看起來就像一個數(shù)組一樣,但是實際上只有在
字節(jié)讀寫的時候才會進行文件輸入輸出操作.
下面給出了如何定義一個索引屬性.
例子
在這個例子中,FileByteArray使得對文件的訪問像字節(jié)數(shù)組一樣. Reverse類把文件的字節(jié)
顛倒過來.你可以就那下面這個程序本身試驗一下,執(zhí)行兩次就恢復原狀了.
000: // Indexers\indexer.cs
001: using System;
002: using System.IO;
003:
004: // Class to provide access to a large file
005: // as if it were a byte array.
006: public class FileByteArray
007: {
008: Stream stream;// Holds the underlying stream
009: // used to access the file.
010: // Create a new FileByteArray encapsulating a particular file.
011: public FileByteArray(string fileName)
012: {
013: stream = new FileStream(fileName, FileMode.Open);
014: }
015:
016: // Close the stream. This should be the last thing done
017: // when you are finished.
018: public void Close()
019: {
020: stream.Close();
021: stream = null;
022: }
023:
024: // Indexer to provide read/write access to the file.
025: public byte this[long index] // long is a 64-bit integer
026: {
027: // Read one byte at offset index and return it.
028: get
029: {
030: byte[] buffer = new byte[1];
031: stream.Seek(index, SeekOrigin.Begin);
032: stream.Read(buffer, 0, 1);
033: return buffer[0];
034: }
035: // Write one byte at offset index and return it.
036: set
037: {
038: byte[] buffer = new byte[1] {value};
039: stream.Seek(index, SeekOrigin.Begin);
040: stream.Write(buffer, 0, 1);
041: }
042: }
043:
044: // Get the total length of the file.
045: public long Length
046: {
047: get {
048: return stream.Seek(0, SeekOrigin.End);
049: }
050: }
051: }
052:
053: // Demonstrate the FileByteArray class.
054: // Reverses the bytes in a file.
055: public class Reverse
056: {
057: public static void Main(String[] args)
058: {
059: // Check for arguments.
060: if (args.Length == 0)
061: {
062: Console.WriteLine("indexer ");
063: return;
064: }
065:
066: FileByteArray file = new FileByteArray(args[0]);
067: long len = file.Length;
068:
069: // Swap bytes in the file to reverse it.
070: for (long i = 0; i < len / 2; ++i)
071: {
072: byte t;
073:
074: // Note that indexing the "file" variable invokes the
075: // indexer on the FileByteStream class, which reads
076: // and writes the bytes in the file.
077: t = file[i];
078: file[i] = file[len - i - 1];
079: file[len - i - 1] = t;
080: }
081:
082: file.Close();
083: }
084: }
運行結(jié)果
用下面的文本文件測試這個程序.
// Indexers\Test.txt
public class Hello1
{
public static void Main()
{
System.Console.WriteLine("Hello, World!");
}
}
編譯并運行程序如下:
indexer Test.txt
type Test.txt
將會產(chǎn)生如下的顯示:
}
}
;)"!dlroW ,olleH"(eniLetirW.elosnoC.metsyS
{
)(niaM diov citats cilbup
{
1olleH ssalc cilbup
txt.tseT\srexednI //
[代碼討論]
* 因為索引使用操作符[],所以注意在聲明的時候使用關(guān)鍵字this,而沒有名字.
* 上面的例子中,定義了一個下標是長整數(shù),返回值是字節(jié)的索引,在get中定義了代碼從一個
文件中讀取一個字節(jié),set中定義了代碼往一個文件中寫入一個字節(jié).
* 一個索引至少要有一個參數(shù).有時候還可以定義多個參數(shù),象一個多維虛擬數(shù)組一樣,但是這
種情況非常少見. 另外,盡管整型參數(shù)是最常見的,但是索引的參數(shù)可以是任何類型.標準的
字典類就提供了一個參數(shù)是object的索引.
* 盡管索引是一個非常強有力的特性,但是,只有在使用數(shù)組形式的訪問有確切的含義時才是合
適的. 例如下面就是一個不恰當?shù)睦?
class Employee
{
// VERY BAD STYLE: using an indexer to access
// the salary of an employee.
public double this[int year]
{
get
{
// return employee's salary for a given year.
}
}
}
仔細體會一下.
* 索引既可以被重載(Overload),也可以被覆蓋(Override).(以后詳細討論)
[高級話題]
如何創(chuàng)建一個"索引屬性"(Indexed Property)?
有的時候,一個類從不同的角度看,可能可以看成不同種類的集合. 一種叫做索引屬性的技術(shù)
就可以使這種對象得到實現(xiàn).
簡單的說, 從字面上,我們可以理解,索引屬性,首先是一個屬性域,其次,它也是一個索引.舉個
例子,假設(shè)你想寫一個類Document,用來封裝一段文本,目的是為了能夠方便地檢查拼寫,這樣你
可以把這段文本看成多個單詞的數(shù)組或者是多條語句的數(shù)組.最簡單地,你可能想要按如下方式
寫檢查拼寫的代碼,
Document d = new Document();
// ...
for (int i = 0; i < d.Words.Count; ++i)
{
if (d.Words[i] == "Peter")
d.Words[i] = "Joe";
}
for (int i = 0; i < d.Sentences.Count; ++i)
{
if (d.Sentences[i] == "Elvis is the king.")
d.Sentences[i] = "Eric Clapton is a guitar god.";
}
下面的代碼給出如何實現(xiàn)這樣一個類.為了實現(xiàn)索引屬性,你應該注意到,這段代碼定義了一個
嵌套類,在嵌套類的內(nèi)部包含了對主類實例的引用.在主類中定義了只讀的域,用于訪問嵌套類
所定義的"虛擬數(shù)組",這兩個域就是索引屬性.
public class Document
{
public struct WordCollection
{
readonly Document document;// The containing document
internal WordCollection(Document d)
{
document = d;
}
public string this[int indexer]
{
get
{
return document.GetNthWord(indexer);
}
set
{
document.SetNthWord(indexer, value);
}
}
public int Count
{
get
{
return document.CountWords();
}
}
}
public struct SentenceCollection
{
readonly Document document;// The containing document
internal SentenceCollection(Document d)
{
document = d;
}
public string this[int indexer] {
get
{
return document.GetNthSentence(indexer);
}
set
{
document.SetNthSentence(indexer, value);
}
}
public int Count
{
get
{
return document.CountSentences();
}
}
}
// Because the types of the fields have indexers,
// these fields appear as "indexed properties"
public readonly WordCollection Words;
public readonly SentenceCollection Sentences;
public Document()
{
Words = new WordCollection(this);
Sentences = new SentenceCollection(this);
}
private string GetNthWord(int index)
{
/* ... */
return "";
}
private void SetNthWord(int index, string w)
{
/* ... */
}
private int CountWords()
{
/* ... */
return 0;
}
private string GetNthSentence(int index)
{
/* ... */
return "";
}
private void SetNthSentence(int index, string s)
{
/* ... */
}
private int CountSentences()
{
/* ... */
return 0;
}
}
注意: 要謹慎地使用這種技術(shù)!不能亂用.只有當數(shù)組抽象具有特定的含義,而且能夠使你的代碼
更加清晰的時候,才應該使用索引或者索引屬性.