Реализация универсального стека с использованием массива в С#

Я реализую общий стек, используя массив. Но я получаю ошибку как:

Невозможно применить индексирование с помощью [] к выражению типа "T"

на линии:

 data[SP] = data;

как исправить проблему? также я проверил эту ссылку:

Не удается применить индексирование к выражению типа "T"

Должен ли я реализовать то же исправление здесь и в моей ситуации? или есть другой лучший вариант?

Вот мой код:

public class MyStack<T> 
{
    private T[] data { get; set; }
    private int SP { get; set; }
    private int Capacity { get; set; }
    public MyStack(int capacity)
    {
        this.Capacity = capacity;
        data = new T[Capacity];
        SP = -1;
        // it works here, dont know why??? ;)
        data[0] = default(T);
    }
    public void Push(T data)
    {
        ++SP;
        if(SP>=Capacity) growArray();
        // This is where i get error.
        data[SP] = data;
    }
    public T Pop()
    {
        if (SP < 0) throw new InvalidOperationException();
        T value = data[SP];
        data[SP] = default(T);
        SP--;
        return value;
    }
    public T Peak()
    {
        if (SP < 0) throw new InvalidOperationException();
        return data[SP];
    }
    private void growArray()
    {
        throw new NotImplementedException();
    }
}

Заранее спасибо.


person Alagesan Palani    schedule 27.12.2012    source источник
comment
Есть ли конкретная причина, по которой вы внедряете стек? Если нет, вы можете просто использовать System.Collections.Generic.Stack<T>   -  person Waldfee    schedule 27.12.2012


Ответы (4)


Вы должны переименовать параметр «данные» в методе (Push) на другое имя.

        public void Push(T d)
        {
         .
         .
         data[SP] = d;
         .
         .

если есть поле и параметр с одинаковым именем, параметр сильнее, или вы можете использовать ключевое слово this и изменить эту строку на:

        this.data[SP] = data;

Кстати, вы можете использовать готовый класс Stack<T> .net, кроме если вы реализуете по образовательным причинам!

Это готовый код .net Stack<T>

person Sawan    schedule 27.12.2012
comment
о чувак! это ошибка коллизии имен, которую я сделал здесь. :( Большое спасибо за указание на это. - person Alagesan Palani; 27.12.2012
comment
Каждый ответ был отклонен, кроме этого, хотя все ответы верны. Разве это не странно... - person Jon B; 27.12.2012
comment
да, это действительно странно, на самом деле я жду, чтобы принять ваш ответ, поскольку вы ответили мне первым. но вы знаете, что stackoverflow не позволяет вам принять ответ в течение 10 минут. :) - person Alagesan Palani; 27.12.2012
comment
Вы делаете сейчас. Вы не сделали несколько минут назад. (Я не минусовал это, к вашему сведению) - person Jon B; 27.12.2012
comment
ххххххх, ничего, у других есть Килосы и Килосы, но это самый бедный! - person Sawan; 27.12.2012

Это проблема области действия, в строке

data[SP] = data;

data в обоих случаях относится к локальному параметру data, который имеет тип T, а не T[], отсюда и ошибка. Вы можете переименовать локальную переменную или явно указать переменную-член, используя this:

this.data[SP] = data;
person Lee    schedule 27.12.2012

Я подозреваю, что вы ожидаете, что data будет означать формальный параметр, когда вы думаете о формальном параметре, и что data будет означать this.data, когда вы думаете о поле. Компилятор C# не может читать ваши мысли; data в этом случае всегда будет означать формальный параметр, который не является массивом.

Вместо «данные» назовите массив «значения», а передаваемое значение — «значение».

Кроме того, допустимо, но необычно использовать частные автоматические свойства вместо частных полей. Есть ли какая-то причина, почему вы это делаете? Большинство людей используют автоматические свойства только для общедоступных, защищенных или внутренних свойств.

person Eric Lippert    schedule 27.12.2012
comment
Красиво.:) спасибо за ответ. Я использую эти свойства как частные, потому что клиент моего стека не должен напрямую обращаться к этим свойствам, кроме как с помощью методов push и pop. какой лучший способ вы предлагаете здесь, Эрик? - person Alagesan Palani; 27.12.2012
comment
@AlagesanPalani: они определенно должны быть частными, но обычно, если вы хотите хранить личные данные, вы должны сказать private T[] values;, а не private T[] values { get; set; };. Первый создает поле, второй создает невидимое приватное поле, а затем оборачивает его в геттер и сеттер свойства. Это не неправильно, но немного странно, поэтому мне интересно, есть ли у вас какая-то конкретная причина для этого. - person Eric Lippert; 27.12.2012
comment
Хорошо, вы хотите сказать, что если вы предоставляете что-то внешнему миру, автоматические свойства являются хорошим кандидатом. если вы пытаетесь что-то скрыть от внешнего мира, сделайте это приватным полем. Как хорошая практика. да конечно. это хорошее обучение. еще раз спасибо. - person Alagesan Palani; 27.12.2012
comment
@EricLippert Я использую частные автоматические свойства по тем же причинам, по которым вы используете общедоступные автоматические свойства, и не понимаю, почему это может показаться странным. Ой, как приятно видеть, что ты пишешь чаще! :) - person asawyer; 27.12.2012
comment
@asawyer: я думаю, что собственность является частью модели. Цвет — это свойство автомобиля, поэтому Color — это свойство класса Car. Вещи, которые есть в модели, являются общедоступной поверхностью типа. Я думаю о поле как о части механизма — как реализуется модель. Вы хотите скрыть механизм и выставить модель, поэтому мне кажется странным скрывать свойство. Не то чтобы неправильно, просто немного странно. - person Eric Lippert; 27.12.2012

У вас есть параметр в Push() с именем data. Компилятор предпочитает использовать более узкую переменную вместо свойства с именем data. Поскольку параметр является T, а не T[], вы не можете получить к нему доступ с помощью индексатора.

Решение состоит в том, чтобы просто переименовать этот параметр или использовать this.data. Настоятельно рекомендую переименовать параметр.

person Jon B    schedule 27.12.2012