c#中索引器实验案例及相关算法和类型设计的思考
案例是要实现一个对文档文本进行字符处理,并能筛选分离出文档中的单词,且可以以序列索引来对其中的单词进行访问和修改
完整代码
View Code
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace 索引2 { class Program { static void Main(string[] args) { Document mydoc = new Document("Hello,I am a Coder!"); for (int i = 0; i < mydoc.Words.Count; i++) Console.Write(mydoc.Words[i]+" "); } } class Document { private char[] TextArray;//声明一个char[]数组,用于存储数据 public WordCollection Words;//声明一个内部WordCollection类型的字段,作为索引属性 public Document(string initialStr)//构造函数 { TextArray = initialStr.ToCharArray(); Words = new WordCollection(this);//以当前实例对象初始化改对象的字段属性 } public class WordCollection//用于获得文档中单词集合的类 { readonly Document document; internal WordCollection(Document d) { document = d; } private bool Getword(char[] text,int begin,int wordcount,out int start,out int length) { int end = text.Length; int count = 0;//初始化符号或空格个数为0 int inword = -1;//初始化inword为-1,作用是提供单词首字母的指针和空格或数字的判别 start = length = 0;//初始化单词位置和长度为0 for (int i = begin; i <= end; ++i)//由外部参数begin开始,遍历字符数组 { bool isLetter = i < end && Char.IsLetterOrDigit(text[i]);//如果非末尾或为字母或数字,则返回true if (inword >= 0)//判读inword是否重置,可以用于跳过空格或符号 { if (!isLetter)//如果为空格或者符号,且前一个字符为单词的末尾 { //与索引器的index值(wordcount)进行判断,这里count遇到空格或符号时才会叠加, //而wordcount则表示单词的索引值,则表示未达到指定位置单词是不会返回的,PS:之所以可以比较,是因为索引值是从0开始计算的 if (count++ == wordcount) { start = inword;//获取inword为单词的起始值位置 length = i - inword;//以当前符号或空格位置减去单词起始位置得到单词长度 return true;//返回true并退出 } //当遇到空格或符号时,又不是指定的单词索引处,则将inword重置为-1 inword = -1; } } else//这里只有为初始状态或当前一个字符为空格或数字才执行 { if (isLetter)//如果为字母或者数字 inword = i;//如果inword为默认值-1或被重置,且当前为字符,即将字符的索引值赋予inword } } return false;//指定位置不存在单词,返回false } 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)) { 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(); } } } public int Count { get { int count = 0, start = 0, length = 0; while (Getword(document.TextArray, start + length, 0, out start, out length))//利用(start+length)定位到前一个单词之后一个字符所在的位置 ++count;//累加所找到的单词的数目 return count; } } } } }
知识整理
1.索引器的使用适合于具有序列数组性质的数据类型,并要在类型中声明一个可以储存序列数组的字段,例如:
class Document { private char[] TextArray;//声明一个char[]数组,用于存储数据 /*...*/ }
2.索引器返回的数据类型与本身的数据类型无关,可以自定义返回类型
class Document { public string this[int index]//索引器,返回string类型数据 { get {/*...*/} } }
3.主类中声明的内部类型,可以作为主类的字段或属性来使用
class Document { private char[] TextArray;//声明一个char[]数组,用于存储数据 public WordCollection Words;//声明一个内部WordCollection类型的字段,作为索引属性 public Document(string initialStr)//构造函数 { TextArray = initialStr.ToCharArray(); Words = new WordCollection(this);//以当前实例对象初始化改对象的字段属性 } public class WordCollection//用于获得文档中单词集合的类 { /*....*/ } }
4.利用out进行传址引用的方式传递参数时,可以帮助外部参数初始化,并且可以继续给其他的方法函数继续调用
public string this[int index]//索引器 { get { int start, length;//声明2个参数 if (Getword(document.TextArray, 0, index, out start, out length))//利用getword判断是否含有单词,并返回start和length的值 { return new string(document.TextArray, start, length);//将start和length的值代入string方法中,并返回值 } else throw new IndexOutOfRangeException(); } }