C# 索引器和委托全面解析(十二)

在 C# 编程中,索引器和委托是非常重要的特性,它们能够让你的代码更加灵活和高效。本文将详细介绍索引器和委托的基本概念、语法、应用场景以及一些高级用法,帮助你更好地理解和使用这些强大的工具。

索引器(Indexer)简介

什么是索引器?

索引器允许你像访问数组一样访问类的成员。通过索引器,你可以使用数组访问运算符 [] 来获取或设置类的成员。这使得类的行为类似于一个“虚拟数组”。

索引器的用途

索引器的行为类似于属性,但它们没有名称,而是使用 this 关键字来指向对象实例。索引器主要用于将类的实例数据分成更小的部分,并索引每个部分,从而实现更灵活的数据访问。

一维索引器的语法

public element-type this[int index] 
{ 
    get { /* 获取值的逻辑 */ } 
    set { /* 设置值的逻辑 */ } 
}

示例:基本索引器

假设我们有一个类 IndexedNames,它包含一个字符串数组 namelist。我们可以为这个类定义一个索引器,以便通过索引访问数组中的元素。

using System;

namespace IndexerApplication
{
    class IndexedNames
    {
        private string[] namelist = new string[size];
        public static int size = 10;

        public IndexedNames()
        {
            for (int i = 0; i < size; i++)
            {
                namelist[i] = "N. A.";
            }
        }

        public string this[int index]
        {
            get
            {
                if (index >= 0 && index <= size - 1)
                {
                    return namelist[index];
                }
                else
                {
                    return "";
                }
            }
            set
            {
                if (index >= 0 && index <= size - 1)
                {
                    namelist[index] = value;
                }
            }
        }

        static void Main(string[] args)
        {
            IndexedNames names = new IndexedNames();
            names[0] = "Zara";
            names[1] = "Riz";
            names[2] = "Nuha";
            names[3] = "Asif";
            names[4] = "Davinder";
            names[5] = "Sunil";
            names[6] = "Rubic";

            for (int i = 0; i < IndexedNames.size; i++)
            {
                Console.WriteLine(names[i]);
            }

            Console.ReadKey();
        }
    }
}

重载索引器

索引器可以被重载,以支持多个参数或不同类型的参数。例如,我们可以为 IndexedNames 类添加一个基于字符串的索引器,用于查找特定名字的索引。

public int this[string name]
{
    get
    {
        for (int index = 0; index < size; index++)
        {
            if (namelist[index] == name)
            {
                return index;
            }
        }
        return -1;
    }
}

示例:重载索引器

using System;

namespace IndexerApplication
{
    class IndexedNames
    {
        private string[] namelist = new string[size];
        public static int size = 10;

        public IndexedNames()
        {
            for (int i = 0; i < size; i++)
            {
                namelist[i] = "N. A.";
            }
        }

        public string this[int index]
        {
            get
            {
                if (index >= 0 && index <= size - 1)
                {
                    return namelist[index];
                }
                else
                {
                    return "";
                }
            }
            set
            {
                if (index >= 0 && index <= size - 1)
                {

                    namelist[index] = value;
                }
            }
        }

        public int this[string name]
        {
            get
            {
                for (int index = 0; index < size; index++)
                {
                    if (namelist[index] == name)
                    {
                        return index;
                    }
                }
                return -1;
            }
        }

        static void Main(string[] args)
        {
            IndexedNames names = new IndexedNames();
            names[0] = "Zara";
            names[1] = "Riz";
            names[2] = "Nuha";
            names[3] = "Asif";
            names[4] = "Davinder";
            names[5] = "Sunil";
            names[6] = "Rubic";

            for (int i = 0; i < IndexedNames.size; i++)
            {
                Console.WriteLine(names[i]);
            }

            Console.WriteLine(names["Nuha"]);

            Console.ReadKey();
        }
    }
}

委托(Delegate)简介

什么是委托?

委托是一种类型安全的函数指针,它可以存储对某个方法的引用。委托允许你在运行时动态地调用方法,常用于事件处理、回调函数等场景。

委托的用途

委托的主要用途包括:

  • 事件处理:用于响应用户界面中的事件。
  • 回调函数:在异步编程中,用于在操作完成后调用某个方法。
  • 多播:允许多个方法被同一个委托调用。

声明委托

委托的声明类似于方法的声明,但它不需要实现方法体。以下是声明委托的基本语法:

public delegate 返回类型 委托名(参数类型 参数名, ...);

示例:声明委托

public delegate int MathOperation(int x, int y);

实例化委托

一旦声明了委托类型,就可以使用 new 关键字创建委托实例,并将其与具体的方法关联起来。

MathOperation add = new MathOperation(AddNumbers);

示例:实例化和使用委托

using System;

namespace DelegateAppl
{
    delegate int NumberChanger(int n);

    class TestDelegate
    {
        static int num = 10;

        public static int AddNum(int p)
        {
            num += p;
            return num;
        }

        public static int MultNum(int q)
        {
            num *= q;
            return num;
        }

        public static int GetNum()
        {
            return num;
        }

        static void Main(string[] args)
        {
            NumberChanger nc1 = new NumberChanger(AddNum);
            NumberChanger nc2 = new NumberChanger(MultNum);

            nc1(25);
            Console.WriteLine("Value of Num: {0}", GetNum());

            nc2(5);
            Console.WriteLine("Value of Num: {0}", GetNum());

            Console.ReadKey();
        }
    }
}

委托的多播

委托对象可以使用 + 运算符进行合并,形成一个多播委托。多播委托在调用时会依次调用其包含的所有方法。

示例:委托的多播

using System;

namespace DelegateAppl
{
    delegate int NumberChanger(int n);

    class TestDelegate
    {
        static int num = 10;

        public static int AddNum(int p)
        {
            num += p;
            return num;
        }

        public static int MultNum(int q)
        {
            num *= q;
            return num;
        }

        public static int GetNum()
        {
            return num;
        }

        static void Main(string[] args)
        {
            NumberChanger nc1 = new NumberChanger(AddNum);

            NumberChanger nc2 = new NumberChanger(MultNum);

            NumberChanger nc = nc1 + nc2;

            nc(5);
            Console.WriteLine("Value of Num: {0}", GetNum());

            Console.ReadKey();
        }
    }
}

移除委托

你可以使用 - 运算符从多播委托中移除某个方法。

示例:移除委托

using System;

public class Program
{
    public delegate void PrintMessage(string message);

    public static void PrintUpperCase(string message)
    {
        Console.WriteLine(message.ToUpper());
    }

    public static void PrintLowerCase(string message)
    {
        Console.WriteLine(message.ToLower());
    }

    public static void Main()
    {
        PrintMessage print = PrintUpperCase;
        print += PrintLowerCase;

        // 移除 PrintLowerCase 方法
        print -= PrintLowerCase;

        // 调用委托(只会调用 PrintUpperCase)
        print("Hello, C#"); // 输出: HELLO, C#
    }
}

委托和事件

委托经常与事件一起使用。事件是一种特殊的委托,用于实现发布-订阅模式。事件通常用于响应用户界面中的操作。

示例:委托和事件

using System;

public class Button
{
    // 定义一个事件
    public event EventHandler Click;

    // 引发事件的方法
    public void OnClick()
    {
        Click?.Invoke(this, EventArgs.Empty);
    }
}

public class Program
{
    public static void Main()
    {
        Button button = new Button();

        // 订阅事件
        button.Click += Button_Click;

        // 引发事件
        button.OnClick(); // 输出 "Button clicked!"
    }

    private static void Button_Click(object sender, EventArgs e)
    {
        Console.WriteLine("Button clicked!");
    }
}

常见的委托类型

C# 提供了一些常用的委托类型,这些委托类型可以简化你的代码。

1. Action

Action 代表不返回值的方法。它可以接受最多 16 个参数。

Action
<string> printMessage = Console.WriteLine;
printMessage("Hello");

2. Func

Func 代表有返回值的方法。它可以接受最多 16 个参数,其中最后一个参数是返回值类型。

Func<int, int, int> add = (x, y) => x + y;
Console.WriteLine(add(3, 4)); // 输出: 7

总结

通过本文,我们详细介绍了 C# 中的索引器和委托,包括它们的基本概念、语法、应用场景以及一些高级用法。希望这些内容能帮助你更好地理解和使用这些强大的工具,提升你的编程技能。如果你有任何疑问或建议,欢迎在评论区留言交流。