C #: Как я могу добавить объект в массив?

#c#

#c#

Вопрос:

Я новичок в C # ООП, и поместить объекты в массив немного сложнее, чем JS. Это мое первое упражнение, любая помощь в том, как поместить объект в массив, приветствуется.

Я надеялся, что результат будет cars = { porsche, mercedes, bmw, punto, ferrari};

Что я делаю не так?

 static void Main(string[] args)
{
    // Create 5 Car Objects and add them to Array
    var porsche = new Car("Porshe", 340);
    var mercedes = new Car("Mercedes", 320);
    var bmw = new Car("BMW", 330);
    var punto = new Car("Punto", 220);
    var ferrari = new Car("Ferrari", 380);

    // Cars to array
    object[] cars = new object[5];
    cars[0] = porsche;
    cars[1] = mercedes;
    cars[2] = bmw;
    cars[3] = punto;
    cars[4] = ferrari;
    
    foreach(var car in cars)
    {
        Console.WriteLine($"some {car}");
    }
}
 

Автомобиль

 class Car
{
    public Car(string model, int speed)
    {
        Model = model;
        Speed = speed;
    }

    public string Model { get; set; }
    public int Speed { get; set; }

    public int CalculateSpeed( int speed, int skill)
    {
        return speed * skill;
    }
}
 

Вывод на консоль:

 some OOP_Car_Human.Car
some OOP_Car_Human.Car
some OOP_Car_Human.Car
some OOP_Car_Human.Car
some OOP_Car_Human.Car
 

Комментарии:

1. Вы правильно добавили их в массив. Вывод заключается в том, что по умолчанию запись в консоль вызывает toString() для объекта, и если вы не переопределили toString(), вы получаете только имя класса.

2. В отличие от Javascript, который является только типизированным (строки, числа, объекты, функции и т. Д.), C # Строго типизирован. Подумайте о том, чтобы сделать ваш массив массивом cars ( var cars = new Car[5]; ) . Вы также можете инициализировать массив при его создании : var cars = new Car[]{porsche, mercedes, bmw, punto, ferrari}; . Обратите внимание, что размер массива устанавливается исходя из количества объектов в инициализации массива таким образом. Как отмечает @Crowcoder, обязательно переопределите ToString в своем Car классе: public override string ToString() {return model;}

3. Что я должен изменить, чтобы исправить ошибку?

4. Console.WriteLine($"some {car.Model}");

5. ах, потому что вам нужно ввести свой массив Car[] cars = new Car[5];

Ответ №1:

Как я упоминал в комментариях, C # строго типизирован. Вместо создания массива объектов (в который можно добавить любой объект любого типа), вместо этого создайте массив автомобилей:

  Car[] cars = new Car[5];
 

Теперь ваш массив не может содержать ничего, кроме Car объектов (или экземпляров Car подклассов). Никто не может сказать cars[2] = new Horse("Secretariat"); (что-то, что можно сделать с object[] массивом.

Вы также можете использовать var вместо:

  var cars = new Car[5];
 

Таким образом, вам не нужно вводить спецификацию типа дважды. Эти два утверждения имеют совершенно одинаковое значение. Вы можете использовать только var тогда, когда тип правой части присваивания может быть выведен компилятором из контекста. Этот тип применяется к переменной с левой стороны.

Вы также можете инициализировать массив при его создании:

 var cars = new Car[] {
     porsche,
     mercedes,
     bmw,
     punto,
     ferrari,
};
 

Когда вы это делаете, вам не нужно включать размер массива в выражение конструктора массива (вы можете, но вам не нужно).

Вы также можете сделать это:

 var cars = new Car[] {
    new Car("Porshe", 340),
    new Car("Mercedes", 320),
    new Car("BMW", 330),
    new Car("Punto", 220),
    new Car("Ferrari", 380),
};
 

Вы не используете имена porshe , mercedes , и т.д., кроме как для инициализации массива, поэтому они вам действительно не нужны. Вы можете использовать их (и это, вероятно, не будет стоить больше во время выполнения, но …)

Как указал @crowcoder, вам действительно следует добавить ToString метод:

 public override string ToString()
{
    return Model;
}
 

Это заставит ваш код вести себя так, как вы ожидаете. Console.WriteLine Метод, когда он передается string , выводит строку. Однако, если ему передается объект любого другого типа, он будет вызывать ToString объект. object Класс объявляется ToString как virtual переопределяемый метод or . object Класс включает в себя реализацию ToString , но единственное, что он знает об объекте, — это тип объекта, поэтому именно его он использует в качестве возвращаемой строки. Поскольку метод является виртуальным / переопределяемым, подклассы object (т. Е. Практически Любого типа) могут переопределять этот метод и делать все, что им заблагорассудится. Вы ожидали, что свойство car Model будет выводиться, так что это то, что это делает.

Другие люди отталкивают вас от массивов в сторону списка. Для этого есть веские причины. Один из них (знакомый программистам Javascript) заключается в том, что список является растянутым; он будет расти по мере добавления объектов (как это делает массив Javascript). Массивы C # обязательно имеют фиксированный размер.

Еще одно замечание. Как вы выяснили, когда у вас был массив объектов, который содержал Cars , безопасность типов C # не позволит вам напрямую вызывать методы, специфичные для Car, для объектов, которые компилятор знает только как объекты. В C # переменная типа as object может ссылаться на что угодно, но у нее есть только очень небольшое количество методов (например ToString ), которые могут быть вызваны для нее напрямую (в отличие от Javascript, где привязка к элементу выполняется во время выполнения, а не во время компиляции).

Если вы хотите получить поведение переменной, подобное Javascript, вы можете использовать dynamic в качестве type ( var cars = new dynamic[]{bmw, etc.} ) . Введенные переменные dynamic могут вести себя очень похоже на переменные Javascript (и есть типы, которые ведут себя почти точно так же, как объекты Javascript (они являются производными от Expando )).

Если у вас есть выражение типа (как вы показали): Console.WriteLine($"some {car.Model}"); , и car оно введено dynamic , то во время выполнения car проверяется тип объекта, чтобы определить, имеет ли он Model свойство. Если это произойдет, он будет оценен. Если этого не происходит, возникает исключение. Все это делается во время выполнения. Ошибка, которую вы видели (CS1061: ‘object’ не содержит определения для ‘Model’), возникает во время компиляции. Из-за безопасности типов Car известно, что a имеет Model свойство, и проверка во время выполнения не требуется.

Тем не менее, почти все, кто следит за тегом C #, скажут вам, что вы не используете dynamic , если у вас нет действительно веской причины. Безопасность типов C # является его большим преимуществом (и как только вы привыкнете к этому, это просто имеет смысл).

Комментарии:

1. Я пишу огромный спил о ToString и object , но это в основном покрывает его. 1

2. И, эй, я выиграл действительно уродливую шляпу для этого. Это моя первая не секретная шляпа (кроме масок социального дистанцирования).

Ответ №2:

Я бы предпочел использовать список.

 List<Car> cars = new List<Car>();
cars.Add(porsche);
cars.Add(mercedes);
...
cars.Add(ferrari);

cars.ForEach(car => {
   Console.WriteLine($"some {car.Model}");
});
 

Если вы хотите превратить его в массив, используйте:

 cars.ToArray();