並不決定INDEXER好用(內付INDEXER的教程 中文版) :)

來源:互聯網
上載者:User
教程|中文 這一課講述如何在C#的類中聲明索引,以使類能象數組一樣被訪問,這樣類的執行個體就能夠使用
數組訪問操作符[]來訪問類對象.
在C#中定義索引和在C++中定義操作符[]類似.對於那些封裝了數組或者使用起來有點象集合
的類,就可以使用索引,這樣使用者就能夠使用訪問數組的文法訪問這個類.
舉個例子,假定,你想要定義一個類,它使得檔案就像一個位元組數組一樣.如果檔案非常大,把
整個檔案都讀入記憶體是不切合實際的,尤其是在你只想讀寫其中一小部分位元組的時候更是如
此.這裡定義了一個類FileByteArray,使檔案看起來就像一個數組一樣,但是實際上只有在
位元組讀寫的時候才會進行檔案輸入輸出操作.

下面給出了如何定義一個索引屬性.

例子

在這個例子中,FileByteArray使得對檔案的訪問像位元組數組一樣. Reverse類把檔案的位元組
顛倒過來.你可以就那下面這個程式本身實驗一下,執行兩次就恢複原狀了.

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: }

運行結果

用下面的文字檔測試這個程式.

// Indexers\Test.txt
public class Hello1
{
    public static void Main()
    {
        System.Console.WriteLine("Hello, World!");
    }
}

編譯並運行程式如下:

indexer Test.txt
type Test.txt

將會產生如下的顯示:

}
}
;)"!dlroW ,olleH"(eniLetirW.elosnoC.metsyS
{
)(niaM diov citats cilbup
{
1olleH ssalc cilbup
txt.tseT\srexednI //

[代碼討論]

* 因為索引使用操作符[],所以注意在聲明的時候使用關鍵字this,而沒有名字.
* 上面的例子中,定義了一個下標是長整數,傳回值是位元組的索引,在get中定義了代碼從一個
檔案中讀取一個位元組,set中定義了代碼往一個檔案中寫入一個位元組.
* 一個索引至少要有一個參數.有時候還可以定義多個參數,象一個多維虛擬數組一樣,但是這
種情況非常少見. 另外,儘管整型參數是最常見的,但是索引的參數可以是任何類型.標準的
字典類就提供了一個參數是object的索引.
* 儘管索引是一個非常強有力的特性,但是,只有在使用數組形式的訪問有確切的含義時才是合
適的. 例如下面就是一個不恰當的例子.

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).(以後詳細討論)

[進階話題]
如何建立一個"索引屬性"(Indexed Property)?

有的時候,一個類從不同的角度看,可能可以看成不同種類的集合. 一種叫做索引屬性的技術
就可以使這種對象得到實現.
簡單的說, 從字面上,我們可以理解,索引屬性,首先是一個屬性域,其次,它也是一個索引.舉個
例子,假設你想寫一個類Document,用來封裝一段文本,目的是為了能夠方便地檢查拼字,這樣你
可以把這段文本看成多個單詞的數組或者是多條語句的數組.最簡單地,你可能想要按如下方式
寫檢查拼字的代碼,

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.";
}

下面的代碼給出如何?這樣一個類.為了實現索引屬性,你應該注意到,這段代碼定義了一個
嵌套類,在嵌套類的內部包含了對主類執行個體的引用.在主類中定義了唯讀域,用於訪問嵌套類
所定義的"虛擬數組",這兩個域就是索引屬性.

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;
    }
}

注意: 要謹慎地使用這種技術!不能亂用.只有當數組抽象具有特定的含義,而且能夠使你的代碼
更加清晰的時候,才應該使用索引或者索引屬性.




相關關鍵詞:
相關文章

E-Commerce Solutions

Leverage the same tools powering the Alibaba Ecosystem

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。