Реальные случаи использования для индексаторов C#?

Я видел много примеров для индексаторов c#, но каким образом это поможет мне в реальных жизненных ситуациях.

Я знаю, что гуру C# не добавил бы это, если бы это не было серьезной особенностью, но я не могу думать о реальной ситуации в мире (а не о барах foo), чтобы использовать индексаторы.

примечание:Я понимаю вопрос существует, но это мне не очень помогает.

14 ответов


то, как я смотрю на индексаторы, это (правильно или неправильно!), доступ к чему-то по индексу должен быть более эффективным, чем доступ к нему любым другим способом, потому что каким-то образом, форма или форма, класс, индексатор которого я использую, хранит некоторую форму индекс это позволяет ему быстро искать значения при доступе таким образом.

классический пример-массив, когда вы обращаетесь к элементу N массива с помощью кода myarray[3], компилятор / интерпретатор знает, насколько большой (по памяти) элементы массива являются и могут рассматривать его как смещение от начала массива. Вы также можете "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, но, как я уже сказал,.. Я всегда ... --3-->рассматривал "индексатор" как целесообразный способ получения данных из чего-то.


наиболее очевидными примерами, как упоминал Скурмедель, являются 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

? Теперь это может быть относительно редко для вас нужно написать индексатор (обычно, когда вы создаете класс, подобный коллекции), но я подозреваю, что вы использовать их достаточно часто.


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);
    }
}

предположим, у вас есть коллекция объектов, которые вы хотите индексировать по чему-то, кроме порядка, в котором они были помещены в коллекцию. В приведенном ниже примере вы можете увидеть, как вы можете использовать свойство "Location" некоторого объекта и с помощью индексатора возвращать все объекты в коллекции, соответствующие вашему местоположению, или во втором примере все объекты, содержащие определенное количество() объектов.

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);}
  }
}

Как только .NET получил дженерики, самая большая причина для меня реализовать индексатор (для реализации строго типизированной коллекции) ушла.


Это просто синтаксический сахар для классов типов коллекций. У меня никогда не было причин писать такой класс. Поэтому я думаю, что в "реальной жизни" это очень редко используется, потому что классы, использующие его, уже реализованы.


In ASP.Net, есть несколько разных случаев, когда индексатор используется, например, чтение чего-либо из любого из объектов запроса, сеанса или приложения. Я часто видел, где что-то хранится в сеансе или объекте приложения только для использования снова и снова.


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();
        }
    }
}

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

индексаторы-это элементы в программе C#, которые позволяют классу вести себя как массив. Вы сможете использовать весь класс в качестве массива. В этом массиве можно хранить переменные любого типа. Переменные хранятся в отдельном месте, но адресованы самим именем класса. Создание индексов для целых чисел, строк, логических и т. д. была бы осуществимая идея. Эти индексаторы будут эффективно действовать на объекты класса.

предположим, вы создали индексатор класса, который хранит номер рулона студента в классе. Далее, предположим, что вы создали объект этого класса с именем obj1. Когда вы говорите obj1[0], Вы имеете в виду первого студента в списке. Аналогично obj1[1] относится ко 2-му студенту по списку.

поэтому объект принимает индексированные значения для ссылки на целочисленную переменную, которая хранится в частном или общедоступном классе. Предположим вам не было этого объекта, тогда вы, вероятно, ссылались бы таким образом (что было бы дольше):

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

где RollNumberVariable будет целочисленной переменной, которая ссылается на номер рулона текущего объекта student.

для больше деталей http://code-kings.blogspot.in/2012/09/indexers-in-c-5.html


вот видео, которое я создал http://www.youtube.com/watch?v=HdtEQqu0yOY и ниже приводится подробное объяснение о том же.

индексаторы помогают получить доступ к содержащейся коллекции в классе с помощью упрощенного интерфейса. Это синтаксический сахар.

например, допустим, у вас есть класс customer с коллекцией адресов внутри него. Теперь предположим, что мы хотели бы получить коллекцию адресов по "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"];

Ура.


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;
        }
    }
}

}


дополнение к @ code-Kings post.

более того, вызов RollNumberVariable[0] вызовет поведение индексатора коллекции по умолчанию. В то время как индексаторы на самом деле свойства, это от вашего имени, чтобы написать свою собственную логику при извлечении данных. Можно легко делегировать большую часть значения параметра индекса во внутреннюю коллекцию, но можно также возвращать любое произвольное значение для определенных значений индекса.

просто пример - вы можете иметь 2+ внутренний коллекции в другом формате, но внешний пользователь будет взаимодействовать с ними через один индексатор (который будет работать как диспетчер), пока эти коллекции будут скрыты. Это в значительной степени поощряет принцип инкапсуляции.


Я пытаюсь получить изображения из файла последовательности. Мне нужен какой-то 2D-массив или зубчатый массив для хранения значений пикселей. Я использую индексаторы вместо массивов, потому что цикл над индексаторами быстрее, чем цикл над 2D или зубчатыми массивами.


вы можете использовать индексатор, чтобы элегантно обеспечить многопоточную синхронизацию чтения / записи с не-потокобезопасным словарем (или любой не-потокобезопасной коллекцией):

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 (или любую другую параллельную коллекцию).