visual C#(十六)使用索引器

参考书:《 visual C# 从入门到精通》
第三部分 用C#定义可扩展类型
第16章 使用索引器

16.1 什么是索引器

我们通常用int来存储整数值。int内部将值存储为32位,每一位为0或1。

C#提供以下操作符来访问和操纵int中单独的二进制位。

  • ~(NOT)操作符:执行按位求补
  • <<(左移位)操作符:二元操作符,向左移位,如204<<2,将返回48
  • |(OR)操作符:二元操作符,执行按位OR
  • &(AND)操作符:执行按位AND
  • ^(XOR)操作符:执行按位XOR(异或)

综合起来我们就可以用一个表达式来判断一个int中单独的位的值。

不如对于类型为int的名为bit`的变量判断位置5(右数第6位)的二进制位是1还是0:

(bits&(1<<5))!=0

又如将位置6的位设为0:bits &=~(1<<5)

将位置6的位设为1:bits|=~(1<<5)

这些例子语法上都没问题的,但看起来很不直观,会提升维护难度。

16.1.2 同一个例子改用索引器

前面我们给出的实例其最佳解决方案应该是将int作为一个32元素的布尔数组,这样我们就可以直接的对每一位进行操作了。但我们并不能直接对int进行操作,所以我们要新建一种类型,它在行为、外观、用法上都类似于bool数组,但它是用int实现的。为此定义一个索引器。如:

struct IntBits{
    private int bits;
    public IntBits(int initialBitValue){
        bits=initialBitValue;
    }
    //在这里写索引器
}

定义索引器要一种兼具属性和数组特征的记号法。由关键字this引入,this前是返回类型,之后是方括号,方括号中指定索引器的索引的类型和形参。如下:

struct IntBits{
    ...;
    public bool this [int index]{
        get{
            return (bits&(1<<index))!=0;
        }
        set{
            if(value)//value为true或false,指定为1或0
                bits|=(1<<index);
            else
                bits&=~(1<<index);
        }
    }
}

注意:

  • 索引器不是方法,他没有一对包含参数的圆括号
  • 所有索引器都用this取代方法名
  • 和属性一样,索引器包含getset两个访问器
  • 索引器声明中指定的index将为getset访问器所用

这样一来我们就可以使用方括号计数法:

int adapted=126;
IntBits bits=new IntBits(adapted);
bool peek=bits[6];
bits[0]=true;
bits[3]=false;

16.1.3 理解索引器的访问器

对索引器读取或者访问时其实是在对getset访问器进行调用。

16.1.4 对比索引器和数组

索引器和数组语法上很相似,但二者存在重要区别:

  • 索引器可以使用非数值下标,但数组只能使用整数下标
  • 索引器能重载,但数组不行
  • 索引器不能作为refout的参数使用,但数组可以

16.2 接口中的索引器

可以在接口中声明索引器:

interface IRawInt{
    bool this[int index]{get;set;}
}

16.3 在Windows应用程序中使用索引器

最后我们又来完成一个实例。

创建一个空白应用项目,先拖放控件如下图所示:
在这里插入图片描述

其中显然有3个TextBlock,3个TextBox,2个Button,底下是CommandBar(命令栏),在CommandBar的属性窗口的公共|Content栏点击新建,找到Button,大致上这样布局。注意3个TextBox都要命名,如最上面的名为message,下面两个命名为namephoneName

3个Button控件设置好click事件的处理方法。

源文件代码如下:

Names.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace C_16_3
{
    class Name
    {
        private readonly string text;

        public string Text
        {
            get { return this.text; }
        }
        public Name()
        {
            this.text = "";
        }
        public Name(string name)
        {
            this.text = name;
        }
    }
}

PhoneNumber.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace C_16_3
{
    class PhoneNumber
    {
        private readonly string text;

        public string Text
        {
            get { return this.text; }
        }
        public PhoneNumber()
        {
            this.text = "";
        }
        public PhoneNumber(string phone)
        {
            this.text = phone;
        }
    }
}

PhotoBook.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace C_16_3
{
    sealed class PhoneBook
    {
        private Name [] names;
        private PhoneNumber[] phonenames;
        private int length = 10;
        private int index = 0;
        public Name this [PhoneNumber number]
        {
            get
            {
                //int i = Array.IndexOf(this.phonenames, number);
                int i = -1;
                for(int x = 0; x < this.index; ++x)
                {
                    if (this.phonenames[x].Text == number.Text)
                    {
                        i = x;
                        break;
                    }
                }
                if (i != -1)
                    return this.names[i];
                else
                    return new Name();
            }
        }
        public override string ToString()
        {
            string texts = "";
            for(int x = 0; x < this.index; ++x)
            {
                texts += $"{x}->{this.names[x].Text}->{this.phonenames[x].Text}\n";
            }
            return texts;
        }
        public PhoneBook()
        {
            names = new Name[length];
            phonenames = new PhoneNumber[length];
        }
        public void enlargeIfFull()
        {
            if (this.index == this.length)
            {
                this.length *= 2;
                Name[] newNames = new Name[this.length];
                PhoneNumber[] newPhoneNumber = new PhoneNumber[this.length];
                for(int x = 0; x < names.Length; ++x)
                {
                    newNames[x] = names[x];
                    newPhoneNumber[x] = phonenames[x];
                }
                names = newNames;
                phonenames = newPhoneNumber;
            }
        }
        public void addItem(string name,string phoneNumber)
        {
            names[index] = new Name(name);
            phonenames[index] = new PhoneNumber(phoneNumber);
            ++index;
        }
        public string getIndex()
        {
            return index.ToString();
        }
        public PhoneNumber this[Name name]
        {
            get
            {
                //int i = Array.IndexOf(this.names, name);
                int i = -1;
                for (int x = 0; x < this.index; ++x)
                {
                    if (this.names[x].Text == name.Text)
                    {
                        i = x;
                        break;
                    }
                }
                if (i != -1)
                    return this.phonenames[i];
                else
                    return new PhoneNumber();
            }
        }
    }
}

最后,MainPage.xaml.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

// https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x804 上介绍了“空白页”项模板

namespace C_16_3
{
    /// <summary>
    /// 可用于自身或导航至 Frame 内部的空白页。
    /// </summary>
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
        }
        private PhoneBook phoneBook = new PhoneBook();
        private void findByNameClick(object sender, RoutedEventArgs e)
        {
            string text = name.Text;
            if (!String.IsNullOrEmpty(text))
            {
                Name personName = new Name(text);
                PhoneNumber personPhoneNumber = this.phoneBook[personName];
                phoneNumber.Text = String.IsNullOrEmpty(personPhoneNumber.Text) ? "Not Found"
                    : personPhoneNumber.Text;
            }
        }

        private void findByNumberClick(object sender, RoutedEventArgs e)
        {
            string text = phoneNumber.Text;
            if (!String.IsNullOrEmpty(text))
            {
                PhoneNumber personsPhoneNumber = new PhoneNumber(text);
                Name personsName = this.phoneBook[personsPhoneNumber];
                name.Text = String.IsNullOrEmpty(personsName.Text) ? "NotFound" 
                    : personsName.Text;
            }
        }

        private void addClick(object sender, RoutedEventArgs e)
        {
            string personName = name.Text;
            string personPhoneNumber = phoneNumber.Text;
            if (!(String.IsNullOrEmpty(personName) || String.IsNullOrEmpty(personPhoneNumber))){
                phoneBook.enlargeIfFull();
                phoneBook.addItem(personName, personPhoneNumber);
                //message.Text += $"{phoneBook.getIndex()}--{name.Text}--{phoneNumber.Text}\n";
            }
            message.Text = this.phoneBook.ToString();
        }
    }
}

运行效果如下:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值