Как перегрузить оператор квадратной скобки в C #?

254

DataGridView, например, позволяет вам сделать это:

DataGridView dgv = ...;
DataGridViewCell cell = dgv[1,5];

но я не могу найти документацию по оператору index / квадратные скобки. Как они это называют? Где это реализовано? Это может бросить? Как я могу сделать то же самое в моих собственных классах?

ETA: Спасибо за все быстрые ответы. Вкратце: соответствующая документация находится в собственности "Item"; способ перегрузки заключается в объявлении свойства как public object this[int x, int y]{ get{...}; set{...} }; индексатор для DataGridView не выбрасывает, по крайней мере, согласно документации. Не упоминается, что произойдет, если вы введете неверные координаты.

ETA Опять же: ОК, хотя в документации об этом ничего не говорится (непослушная Microsoft!), Оказывается, что индексатор для DataGridView фактически выдает исключение ArgumentOutOfRangeException, если вы передадите ему недопустимые координаты. Честное предупреждение.

Coderer
источник

Ответы:

374

Вы можете найти, как это сделать здесь . Короче это:

public object this[int i]
{
    get { return InnerList[i]; }
    set { InnerList[i] = value; }
}

Если вам нужен только геттер, можно также использовать синтаксис в ответе ниже (начиная с C # 6).

Ruben
источник
9
небольшой комментарий: в зависимости от того, что вы делаете, вы можете найти более подходящим сделать: get {return base [i]; } set {base [i] = value; }
MikeBaz - MSFT
7
Это не перегрузка оператора. Это индексатор
Деструктор
5
Индексатор также может быть унарным оператором.
alan2 здесь
1
В 2019 году должен быть выбран новый ответ, этот . Жаль, что у SO нет возможности иметь дело с устаревшими ответами, так как новый не близок к получению 350+ голосов, хотя и заслуживает их.
минута
@mins Я включил ссылку на другой ответ.
Рубен
41

Это будет свойство элемента: http://msdn.microsoft.com/en-us/library/0ebtbkkc.aspx

Может быть, что-то вроде этого будет работать:

public T Item[int index, int y]
{ 
    //Then do whatever you need to return/set here.
    get; set; 
}
Рикардо Вильямиль
источник
Большое спасибо! Если бы я мог задать два ответа, я бы добавил и ваш - никто другой не знал, что нужно искать Предмет в документации ...
Coderer
5
С точки зрения того, как это реализовано, это «Предмет», но в терминах C # это «это»
Марк Гравелл
1
Правильно, но я спросил: «На всю жизнь я не могу найти документацию по оператору индекса / квадратной скобки» - я имел в виду, когда вы просматриваете библиотечный класс в MSDN, где они говорят вам об операторе? Вот почему я сделал это последнее "ETA" о том, что он бросает - документы не так .
Coderer
26
Operators                           Overloadability

+, -, *, /, %, &, |, <<, >>         All C# binary operators can be overloaded.

+, -, !,  ~, ++, --, true, false    All C# unary operators can be overloaded.

==, !=, <, >, <= , >=               All relational operators can be overloaded, 
                                    but only as pairs.

&&, ||                  They can't be overloaded

() (Conversion operator)        They can't be overloaded

+=, -=, *=, /=, %=                  These compound assignment operators can be 
                                    overloaded. But in C#, these operators are
                                    automatically overloaded when the respective
                                    binary operator is overloaded.

=, . , ?:, ->, new, is, as, sizeof  These operators can't be overloaded

    [ ]                             Can be overloaded but not always!

Источник информации

Для кронштейна:

public Object this[int index]
{

}

НО

Оператор индексации массива не может быть перегружен ; однако типы могут определять индексаторы, свойства, которые принимают один или несколько параметров. Параметры индексатора заключены в квадратные скобки, как и индексы массива, но параметры индексатора могут быть объявлены любого типа (в отличие от индексов массива, которые должны быть целыми).

Из MSDN

Патрик Дежарден
источник
да, он может быть перегружен, если сигнатура параметра отличается, точно так же, как ограничения на перегрузку любого другого метода
Чарльз Бретана,
Может, но не для того состояния, которое я написал. Это из MSDN. Проверьте источник, если вы мне не верите
Патрик Дежарден
1
Извините, если я неправильно прочитал ваш пост, но на какое условие вы ссылаетесь?
Чарльз Бретана
+1 за удобный список. К вашему сведению, ссылка умерла. (4 года спустя, я знаю)
Mixxiphoid
Я хотел бы добавить, что теперь вы можете переопределять как неявное, так и явное приведение типов в C #.
Felype
9

Если вы используете C # 6 или новее, вы можете использовать синтаксис тела выражения для индексатора только для получения:

public object this[int i] => this.InnerList[i];

амосс
источник
6
public class CustomCollection : List<Object>
{
    public Object this[int index]
    {
        // ...
    }
}
Джейсон Месьончек
источник
5
На самом деле, это действительно опасно - теперь у вас есть две конкурирующие реализации: любой с переменной, типизированной как List <T> или IList <T> или IList и т. Д., Не будет выполнять ваш пользовательский код.
Марк Гравелл
1
Согласились - если не больше, нет необходимости извлекать вашу CustomCollection из Списка, но я не осознавал, что это на самом деле опасно
Coderer
Тем не менее, он по-прежнему будет выполнять пользовательский код, не так ли? Неважно, какой тип переменной вы объявляете - важен тип объекта.
IZB
1
Дружеское напоминание о полиморфизме C #: это происходит потому, что базовый класс не объявляет свою реализацию виртуальной. Если бы он был объявлен как виртуальный, пользовательский код вызывался бы в каждом случае.
almulo
1
Кроме того, этот код выдаст вам предупреждение компилятора, так как оба индексатора не являются виртуальными. Компилятор предложит вам указать ваш пользовательский индексатор по newключевому слову.
amoss
4

Для CLI C ++ (скомпилировано с / clr) смотрите эту ссылку MSDN .

Вкратце, свойству может быть присвоено имя «default»:

ref class Class
{
 public:
  property System::String^ default[int i]
  {
    System::String^ get(int i) { return "hello world"; }
  }
};

источник
2

Вот пример, возвращающий значение из внутреннего объекта List. Должен дать вам идею.

  public object this[int index]
  {
     get { return ( List[index] ); }
     set { List[index] = value; }
  }
Роб Проуз
источник
1

Если вы имеете в виду индексатор массива, вы перегружаете его, просто записывая свойство индексатора. И вы можете перегружать (записывать столько, сколько хотите) свойств индексатора, если каждый из них имеет свою сигнатуру параметра

public class EmployeeCollection: List<Employee>
{
    public Employee this[int employeeId]
    {   
        get 
        { 
            foreach(var emp in this)
            {
                if (emp.EmployeeId == employeeId)
                    return emp;
            }

            return null;
        }
    }

    public Employee this[string employeeName]
    {   
        get 
        { 
            foreach(var emp in this)
            {
                if (emp.Name == employeeName)
                    return emp;
            }

            return null;
        }
    }
}
Чарльз Бретана
источник
2
Во-первых, вы имеете в виду это [], а не это () - однако предоставление пользовательского (но другого) этого [int] для чего-то, что является списком (IList / IList <T> / List <T>), довольно опасно - и может привести к незначительным ошибкам между версиями int index и int employeeId. Оба все еще могут быть вызваны.
Марк Гравелл
и на самом деле, я не думаю, что код, который я ввел выше, скомпилируется без добавления нового оператора или оператора переопределения именно из-за существования реализации List [T> этого [int]. Вы правы в отношении потенциала при этом, просто подразумевали это как пример перегрузки индексатора.
Чарльз Бретана