49

我已经看过很多关于 c# Indexers 的示例,但它在现实生活中会以何种方式帮助我。

我知道如果它不是一个严肃的功能,C# 大师就不会添加它,但我想不出现实世界的情况(不是 foo bar 的东西)来使用索引器。

注意:我意识到存在一个相关的问题,但这对我没有多大帮助。

4

14 回答 14

34

我看待索引器的方式是(正确或错误!),通过索引访问某些内容应该比以任何其他方式访问它更有效,因为以某种方式,形状或形式,我正在使用其索引器的类存储某种形式的索引,允许它在以这种方式访问​​时快速查找值。

经典示例是数组,当您使用代码 myarray[3] 访问数组的元素 n 时,编译器/解释器知道数组的(内存方面)元素有多大,并且可以将其视为与数组的开始。你也可以"for(int i = 0; i < myarray.length; i++) { if (i = 3) then { .. do stuff } }"(不是你想要的!),这会降低效率。它还显示了数组是一个不好的例子。

假设您有一个存储类,嗯,DVD,所以:

public class DVDCollection
{
    private Dictionary<string, DVD> store = null;
    private Dictionary<ProductId, string> dvdsByProductId = null;

    public DVDCollection()
    {
        // gets DVD data from somewhere and stores it *by* TITLE in "store"
        // stores a lookup set of DVD ProductId's and names in "dvdsByProductid"
        store = new Dictionary<string, DVD>();
        dvdsByProductId = new Dictionary<ProductId, string>();
    }

    // Get the DVD concerned, using an index, by product Id
    public DVD this[ProductId index]  
    {
       var title = dvdsByProductId[index];
       return store[title];
    }
}

只是我的 2p,但是,就像我说的,.. 我一直认为“索引器”是一种从某物中获取数据的权宜之计。

于 2010-02-02T15:28:33.840 回答
25

正如 Skurmedel 所提到的,最明显的例子是List<T>Dictionary<TKey, TValue>。你更喜欢什么:

List<string> list = new List<string> { "a", "b", "c" };
string value = list[1]; // This is using an indexer

Dictionary<string, string> dictionary = new Dictionary<string, string>
{
    { "foo", "bar" },
    { "x", "y" }
};
string value = dictionary["x"]; // This is using an indexer

? 现在,您可能需要编写一个索引器(通常在您创建一个类似集合的类时)相对较少,但我怀疑您会经常使用它们。

于 2010-02-02T15:26:12.543 回答
10

Microsoft有一个使用索引器将文件视为字节数组的示例。

public byte this[long index]
{
    // Read one byte at offset index and return it.
    get 
    {
        byte[] buffer = new byte[1];
        stream.Seek(index, SeekOrigin.Begin);
        stream.Read(buffer, 0, 1);
        return buffer[0];
    }
    // Write one byte at offset index and return it.
    set 
    {
        byte[] buffer = new byte[1] {value};
        stream.Seek(index, SeekOrigin.Begin);
        stream.Write(buffer, 0, 1);
    }
}
于 2010-02-02T15:21:51.573 回答
7

假设您有一个对象集合,您希望能够按其在集合中的放置顺序以外的方式对其进行索引。在下面的示例中,您可以看到如何使用某个对象的“位置”属性并使用索引器,返回集合中与您的位置匹配的所有对象,或者在第二个示例中,所有包含某个 Count( ) 对象。

class MyCollection {

  public IEnumerable<MyObject> this[string indexer] {
    get{ return this.Where(p => p.Location == indexer); }
  }

  public IEnumerable<MyObject> this[int size] {
    get{ return this.Where(p => p.Count() == size);}
  }
}
于 2010-02-02T15:19:17.713 回答
5

一旦 .NET 有了泛型,我实现索引器(实现强类型集合)的最大原因就消失了。

于 2010-02-02T15:19:36.487 回答
3

它只是集合类型类的语法糖。我从来没有理由写这样一门课。所以我认为在“现实生活”中很少使用它,因为使用它的类已经实现了。

于 2010-02-02T15:23:02.323 回答
3

在 ASP.Net 中,有几个不同的时间使用索引器,例如从任何请求、会话或应用程序对象中读取内容。我经常看到某些东西存储在 Session 或 Application 对象中,只是为了一次又一次地使用。

于 2010-02-02T15:33:39.767 回答
2
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IndexerSample
{
    class FailSoftArray 
    {
        int[] a; // reference to underlying array
        public int Length; // Length is public
        public bool ErrFlag; // indicates outcome of last operation
        // Construct array given its size.
        public FailSoftArray(int size)
        {
            a = new int[size];
            Length = size;
        }
        // This is the indexer for FailSoftArray.
        public int this[int index] 
        {
        // This is the get accessor.
            get
            {
                if (ok(index))
                {
                    ErrFlag = false;
                    return a[index];
                }
                else
                {
                    ErrFlag = true;
                    return 0;
                }
            }
            // This is the set accessor.
            set
            {
                if (ok(index))
                {
                    a[index] = value;
                    ErrFlag = false;
                }
                else ErrFlag = true;
            }
        }
        // Return true if index is within bounds.
        private bool ok(int index)
        {
            if (index >= 0 & index < Length) return true;
            return false;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            FailSoftArray fs = new FailSoftArray(5);
            int x;
            // Show quiet failures.
            Console.WriteLine("Fail quietly.");
            for (int i = 0; i < (fs.Length * 2); i++)
                fs[i] = i * 10;
            for (int i = 0; i < (fs.Length * 2); i++)
            {
                x = fs[i];
                if (x != -1) Console.Write(x + " ");
            }
            Console.WriteLine();
            // Now, display failures.
            Console.WriteLine("\nFail with error reports.");
            for (int i = 0; i < (fs.Length * 2); i++)
            {
                fs[i] = i * 10;
                if (fs.ErrFlag)
                    Console.WriteLine("fs[" + i + "] out-of-bounds");
            }
            for (int i = 0; i < (fs.Length * 2); i++)
            {
                x = fs[i];
                if (!fs.ErrFlag) Console.Write(x + " ");
                else
                    Console.WriteLine("fs[" + i + "] out-of-bounds");
            }
            Console.ReadLine();
        }
    }
}
于 2011-05-03T11:51:38.787 回答
2

http://code-kings.blogspot.in/2012/09/indexers-in-c-5.html

索引器是 C# 程序中允许类作为数组的元素。您将能够将整个类用作数组。在这个数组中,您可以存储任何类型的变量。变量存储在单独的位置,但由类名本身寻址。为整数、字符串、布尔值等创建索引器将是一个可行的想法。这些索引器将有效地作用于类的对象。

假设您创建了一个班级索引器,用于存储班级中学生的卷号。此外,假设您已经创建了一个名为 obj1 的类的对象。当您说 obj1[0] 时,您指的是卷上的第一个学生。同样 obj1[1] 指的是第二个学生。

因此,该对象采用索引值来引用私有或公开存储在类中的 Integer 变量。假设您没有此功能,那么您可能会以这种方式引用(会更长):

obj1.RollNumberVariable[0]
obj1.RollNumberVariable[1]. 

其中 RollNumberVariable 是表示当前学生对象的卷号的整数变量。

更多详情http://code-kings.blogspot.in/2012/09/indexers-in-c-5.html

于 2012-10-11T08:10:26.750 回答
1

这是我创建的视频http://www.youtube.com/watch?v=HdtEQqu0yOY和下面是关于相同的详细说明。

索引器有助于使用简化的接口在类中访问包含的集合。它是一种语法糖。

例如,假设您有一个客户类,其中包含地址集合。现在假设我们想通过“Pincode”和“PhoneNumber”来获取地址集合。因此,合乎逻辑的步骤是,您将创建两个重载函数,一个使用“PhoneNumber”获取,另一个使用“PinCode”获取。您可以在下面的代码中看到我们定义了两个函数。

Customer Customers = new Customer();
Customers.getAddress(1001);
Customers.getAddress("9090");

如果您使用索引器,您可以使用以下代码所示的内容来简化上面的代码。

Customer Customers = new Customer();
Address o = Customers[10001];
o = Customers["4320948"];

干杯。

于 2013-04-18T01:47:04.880 回答
1

您可以使用索引器优雅地为非线程安全字典(或任何非线程安全集合)提供读/写多线程同步:

internal class ThreadSafeIndexerClass
{
    public object this[int key]
    {
        get
        {
            // Aquire returns IDisposable and does Enter() Exit() on a certain ReaderWriterLockSlim instance
            using (_readLock.Aquire()) 
            {
                object subset;
                _dictionary.TryGetValue(key, out foundValue);
                return foundValue;
            }
        }
        set
        {
            // Aquire returns IDisposable and does Enter() Exit() on a certain ReaderWriterLockSlim instance
            using (_writeLock.Aquire())
                _dictionary[key] = value;
        }
    }
}

特别是当您不想使用重量级 ConcurrentDictionary(或任何其他并发集合)时很有用。

于 2016-11-01T17:15:28.397 回答
0

http://code-kings.blogspot.in/2012/09/indexers-in-c-5.html

使用系统;

命名空间 Indexers_Example

{

class Indexers
{

    private Int16[] RollNumberVariable;

    public Indexers(Int16 size)
    {
        RollNumberVariable = new Int16[size];

        for (int i = 0; i < size; i++)
        {
            RollNumberVariable[i] = 0;
        }
    }

    public Int16 this[int pos]
    {
        get
        {
            return RollNumberVariable[pos];
        }
        set
        {
            RollNumberVariable[pos] = value;
        }
    }
}

}

于 2012-10-11T08:16:58.213 回答
0

除了@code-kings 帖子。

此外,调用RollNumberVariable[0]将触发默认集合的索引器的行为。虽然索引器实际上是属性,但它代表您在提取数据时编写自己的逻辑。您可以轻松地将大部分索引参数值委托给内部集合,但您也可以为某些索引值返回任意值。

只是一个例子 - 你可以有 2+ 个不同格式的内部集合,但外部用户将通过单个索引器与它们交互(这将作为一个调度程序工作),而这些集合将被隐藏。这非常鼓励封装原则。

于 2012-10-11T08:30:38.833 回答
0

我正在尝试从序列文件中获取图像。我需要某种二维数组或锯齿状数组来保存像素值。我使用索引器而不是数组,因为在索引器上循环比在 2D 或锯齿状数组上循环更快。

于 2014-08-04T22:21:20.723 回答