2

I'm new with C# OOP, and it's a little bit more difficult than JS to put Objects into Array. This is my first exercise, any help on how to put an object into an array is appreciated.

I was hoping the output be cars = { porsche, mercedes, bmw, punto, ferrari};

What I'm doing wrong?

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

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

Console Output:

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
7
  • You have added them into the array correctly. The output is because, by default, wrting to console will call ToString() on the object and if you have not overridden ToString() you only get the class name. Commented Dec 19, 2020 at 0:07
  • Unlike Javascript, which is only kinda-sorta typed (strings, numbers, objects, functions, etc.), C# is strongly typed. Consider making your array an array of cars (var cars = new Car[5];). You can also initialize an array when you construct it: var cars = new Car[]{porsche, mercedes, bmw, punto, ferrari};. Note the array size gets set from the number of objects in the array initialization that way. As @Crowcoder notes, make sure to override ToString in your Car class: public override string ToString() {return model;} Commented Dec 19, 2020 at 0:12
  • What should I change to fix the mistake? Commented Dec 19, 2020 at 0:14
  • Console.WriteLine($"some {car.Model}"); Commented Dec 19, 2020 at 0:15
  • 3
    ahh because you need to type your array Car[] cars = new Car[5]; Commented Dec 19, 2020 at 0:24

2 Answers 2

5

As I mentioned in the comments, C# is strongly typed. Instead of creating an array of objects (into which any object of any type can be added), instead, create an array of cars:

 Car[] cars = new Car[5];

Now, your array can contain nothing but Car objects (or instances of Car sub-classes). No one can say cars[2] = new Horse("Secretariat"); (something that can be done with a object[] array.

You can also use var instead:

 var cars = new Car[5];

That way, you don't have to type the type specification twice. The two statements have completely the same meaning. You can only use var when the type of the right-hand side of the assignment can be deduced by the compiler from context. That type is applied to the variable on the left-hand side.

You can also initialize an array when you create it:

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

When you do that, you don't have to include the array size in the array constructor expression (you can, but you don't have to).

You can also do this:

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

You don't use the names porshe, mercedes, etc. other than for the array initialization, so you don't really need them. You can use them (and it likely won't cost any more at runtime, but...)

As @crowcoder has pointed out, you really should add a ToString method:

public override string ToString()
{
    return Model;
}

That will make your code behave the way you expect. The Console.WriteLine method, when it's passed a string will output a string. However, if it is passed an object of any other type, it will call ToString on the object. The object class declares ToString as a virtual or overridable method. The object class includes an implementation of ToString, but the only thing it knows about an object is the type of the object, so that is what it uses as the returned string. Since the method is virtual/overridable, sub-classes of object (i.e., just about every type) can override that method and do whatever they'd like. Your expectation was that the car's Model property would be output, so that's what this does.

Other folks are pushing you away from arrays and towards List. There are good reasons to do this. One of them (familiar to Javascript programmers) is that List is stretchy; it will grow as you add things (like a Javascript array does). C# arrays are necessarily fixed size.

One other note. As you found out when you had an array of objects that contained Cars, C#'s type-safety will prevent you from directly calling Car-specific methods on objects that the compiler knows only as objects. In C#, a variable types as object can refer to anything, but it only has a very small number of methods (like ToString) that can be called on it directly (unlike Javascript, where member binding is done at runtime rather than compile time).

If you want to get Javascript-like variable behavior, you can use dynamic as the type (var cars = new dynamic[]{bmw, etc.}). Variables typed dynamic can behave very much like Javascript variables (and there are types that behave nearly exactly like Javascript objects (they derive from Expando)).

If you have an expression like (like you showed): Console.WriteLine($"some {car.Model}");, and car is typed dynamic, then, at runtime, the type of car is examined to determine if it has a Model property. If it does, it is evaluated. If it doesn't, it throws an exception. All this is done at runtime. They error that you saw (CS1061:'object' does not contain a definition for 'Model') happens at compile time. Because of type-safety, a Car is known to have a Model property and no-runtime check needs to be done.

That said, nearly everyone monitoring the C# tag will tell you dont' use dynamic unless you have a really good reason to. C#'s type-safety is its big advantage (and once you get used to it, it just makes sense).

Sign up to request clarification or add additional context in comments.

2 Comments

I writing a huge spiel about ToString and object but this basically covers it. +1
And, hey, I won a really ugly hat for this. It's my first non-secret hat (other than the social distancing masks).
1

I'd go for using a List.

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

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

If you want to turn it into an array, use:

cars.ToArray();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.