A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 于振发 中级黑马   /  2013-9-27 20:57  /  1339 人查看  /  3 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 于振发 于 2013-9-28 16:48 编辑

      初步了解到索引的概念,但是其原理不太清楚,请各位高手指点江山!

评分

参与人数 1技术分 +1 收起 理由
茹化肖 + 1 赞一个!

查看全部评分

3 个回复

正序浏览
C#语言一个最令人感兴趣的地方就是类的索引器(indexer)。简单说来,所谓索引器就是一类特殊的属性,通过它们你就可以像引用数组一样引用自己的类。显然,这一功能在创建集合类的场合特别有用,而在其他某些情况下,比如处理大型文件或者抽象某些有限资源等,能让类具有类似数组的行为当然也是非常有用的。本文就会引领你设置类来采用索引器。但是,首先让我们概述下属性这个概念以便了解些必要的背景知识。
属性
假如你曾经用VB6编写过程序,那么你应该很熟悉属性方法才对,所谓属性方法其实就是特殊的类成员,它实现了对私有类域的受控访问。在C#语言中有两种属性方法,其一是get,通过它可以返回私有域的值,其二是set,通过它就可以设置私有域的值。比如说,以下面的代码为例,其间创建了一个FirstName 属性,由它控制对私有类成员firstname的访问:

class Person {
PRivate string firstname;
public string FirstName {
get {return firstname;}
set {firstname = value;}
}
}
属性声明可以如下编码:
Person p = new Person();
p.FirstName = "Lamont";
Console.WriteLine (p.FirstName);  


如你你所看到的那样,属性声明倒更像是域声明,只不过它还声明了两个特殊的成员,按照微软的说法就是所谓的访问函数(accessor)。当某一表达式的右边调用属性或者属性用作其他子程序(或者函数)的参数时即会调用get访问函数。反之,当表达式左边调用属性并且通过隐式传递value参数设置私有域值的情况下就会调用set访问函数。你可以创建只读属性,方法是省略set访问函数,这样任何设置属性的尝试都会产生编译错误。
采用索引器的益处

下面是它的结构

<modifier> <return type> this [argument list]
...{
get
...{
// Get codes goes here
}
set
...{
// Set codes goes here
}
}


注:

modifier:修饰词,如private, public, protected or internal

this:在C#中this是一个特殊的关键字,它表示引用类的当前实例。在这里它的意思是当前类的索引。

argument list:这里指索引器的参数。

说了半天咱们转到正题上来,那么为什么我要兜这个圈子呢?其实,这是因为类的索引器非常像属性,从代码上看也是这样。以下是具有索引器的类示例,通过索引器会返回一个字符串:

class Sample {
public string this [int index] {
get {return "You passed " + index; }
}
}  


注意,这里的属性名是this,意思是回引类的当前实例,参数列表包含在方括号而非括号之内。还有,这是一个只读索引器。为了把它改成读/写类型,我又添加了一个set访问函数。在定义索引器的时候,你不一定只采用一个参数。索引器参数可以采用任何类型,不过int是通常采用也是最为合理的类型。同一类中还可能拥有一个以上的索引器(重载)。
如上定义了Sample类之后,我们就可以把索引器用作某种默认的属性,如下所示:

Sample s = new Sample();
Console.WriteLine(s[55]);  


属性和索引器
属性和索引器之间有好些差别:
类的每一个属性都必须拥有唯一的名称,而类里定义的每一个索引器都必须拥有唯一的签名(signature)或者参数列表(这样就可以实现索引器重载)。
属性可以是static(静态的)而索引器则必须是实例成员。
为索引器定义的访问函数可以访问传递给索引器的参数,而属性访问函数则没有参数。
接口
类似数组的行为常受到程序实现者的喜爱,所以你还可以为接口定义索引器,IList和 IDictionary集合接口都声明了索引器以便访问其存储的项目。
在为接口声明索引器的时候,记住声明只是表示索引器的存在。你只需要提供恰当的访问函数即可,不必包括范围修饰符。以下代码把索引器声明为接口IImplementMe的一部分:

interface IImplementMe {
string this[int index]
{
get;
set;
}  


相应实现的类则必须为IimplementMe的索引器具体定义get和set访问函数。
以上就是有关索引器的一些基本概述了。现在你应该对索引器在你的开发中所具有的作用有了较深入的了解。

class SampleCollection<T>
{
    private T[] arr = new T[100];
    public T this[int i]
    {
        get
        {
            return arr[i];
        }
        set
        {
            arr[i] = value;
        }
    }
}

// This class shows how client code uses the indexer
class Program
{
    static void Main(string[] args)
    {
        SampleCollection<string> stringCollection = new SampleCollection<string>();
        stringCollection[0] = "Hello, World";
        System.Console.WriteLine(stringCollection[0]);
    }
}

评分

参与人数 1技术分 +1 收起 理由
茹化肖 + 1 赞一个!

查看全部评分

回复 使用道具 举报
本帖最后由 段朝骞 于 2013-9-27 22:45 编辑

索引器允许类或结构的实例就像数组一样进行索引。
索引器类似于 属性,不同之处在于它们的访问器采用参数。
例如:
class SuoYinQi<T>
{
   private T[] arr = new T(10);
   public this [int i]
   {
        get { return arr; }
        set {arr=value;  }
   }
}
class Program
{
    static void Main(string[] args)
    {
       SuoYinQi<string> str = new SuoYinQi<string>();
       str[0]="abc";
       Console.WriteLine(str[0]);    //打印出abc
       Console.ReadKey();
    }
}


使用索引器可以用类似于数组的方式为对象建立索引。
get 访问器返回值。
set 访问器分配值。
this 关键字用于定义索引器。
value 关键字用于定义由 set 索引器分配的值。
索引器不必根据整数值进行索引,由您决定如何定义特定的查找机制。
索引器可被重载。
索引器可以有多个形参,例如当访问二维数组时。
索引器的脚标可以为其它类型参数,例如:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace 索引器
{
    class Program
    {
        static void Main(string[] args)
        {
            SYQ<string> str = new SYQ<string>();
            str["t1"] = "hello";
            str["t2"] = "World";
            str["t3"] = "c#";
            Console.WriteLine(str["t1"]);
            Console.WriteLine(str["t2"]);
            Console.WriteLine(str["t3"]);
            Console.ReadKey();
        }

    }
    class SYQ<T>
    {
        private T t1;
        private T t2;
        public T this[string str]
        {
            get
            {
                switch(str)
                {
                    case "t1" :
                    return t1 ;
                    case "t2" :
                    return t2;
                    default: return default(T);
                 }
             }
            set
            {
                switch (str)
                {
                    case "t1":
                        t1 = value;
                        break;
                    case"t2":
                        t2 = value;
                        break;
                    //default: Console.WriteLine("不存在"); break;
                }
            }
        }
    }
}


评分

参与人数 1技术分 +1 收起 理由
茹化肖 + 1

查看全部评分

回复 使用道具 举报
首先谢谢你的提问。。。其实我也不怎么明白,但是恶补了下面向对象的视频,还是说下。。

索引器,主要用于封装内部集合或数组的类型中实现的。像数组通过下标来访问指定数组元素的值,这就是索引器的使用形式。其具体类内部的实现,其实和属性相似。

定义索引器   
string this[int index]
{
     get{}
     set{}
}
下面附上代码(参考传智播客-c#面向对象17节索引器)
  1. static void Main(string[] args)
  2.         {
  3.             int[] i = { 23, 34, 656, 87, 09 };
  4.             int x = i[1];   //其实这里数组使用的下标,就是索引器的一种使用形式

  5.             #region  使用自定义的索引器

  6.             Person p1 = new Person();

  7.             p1[1] = "小明";  //通过索引来赋值。
  8.             Console.WriteLine("第一个人叫{0},第二个人叫{1}",p1[1],p1[2]);//通过结果可以看到,我们成功通过索引改变了私有字段firstName的值,得到了secondName的值
  9.                                                                           

  10.             Console.ReadKey();
  11.             #endregion

  12.         }
  13.         /// <summary>
  14.         /// 定义一个Person类,在其内部模拟索引器实现。
  15.         /// </summary>
  16.         class Person
  17.         {
  18.             private string firstName ="大毛";    //定义两个私有字段
  19.             private string secondName = "二毛";

  20.             public string this[int index]   //这是实现索引器,string为索引器类型,this指Person类
  21.             {
  22.                 set             //其内部通过索引对私有字段赋值
  23.                 {
  24.                     if (index == 1)     //当index值为1时,设置firstName的值
  25.                     {
  26.                         firstName = value;
  27.                     }
  28.                     else if (index == 2)
  29.                     {
  30.                         secondName = value;
  31.                     }
  32.                     else
  33.                     {
  34.                         throw new Exception("错误的序号");
  35.                     }
  36.                 }
  37.                 get             //其内部实现得到私有字段的值
  38.                 {
  39.                     if (index == 1)
  40.                     {
  41.                         return firstName;
  42.                     }
  43.                     else if (index == 2)
  44.                     {
  45.                         return secondName;
  46.                     }
  47.                     else
  48.                     {
  49.                         throw new Exception("错误的序号");
  50.                     }
  51.                 }
  52.             }
  53.         }
复制代码
希望能帮到你。。。

评分

参与人数 1技术分 +1 收起 理由
茹化肖 + 1

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马