I have a class named car, with properties color, and year. I'm trying to create an update method, so that it updates only the parameters provided, which can be color, year or both, but if no parameters are given, the car object remains with the old properties.
Here's what I've done
internal class car
{
public car()
{
}
public car Update(string arg_color = null, int? arg_year = null)
{
//Problem is here, I want it to keep the old color when I use SomeOldCar.Update(*DifferentYear*)
car NewCar = new car();
NewCar.color = arg_color;
NewCar.year = arg_year;
return car;
}
public string? color { get; set; }
public int? year { get; set; }
}
Before answering your question - which I'll do at the end - there are a few different concepts you've mixed together that would be helpful to separate out and understand first.
Your color
and year
properties have both get and set methods. This means anyone can update them, without even needing your Update
method, just like this:
Car myCar = new Car();
myCar.Color = "Red";
So technically you've already achieved your objective without even needing your Update
method; albeit maybe accidentally.
It's perfectly valid to have an Update method like you've done. This is often used when there is significant validation (i.e. checking) logic that you need to do, before allowing a new value to be assigned. Rewriting your car
class to demonstrate a check:
public class Car
{
public string? Color { get; private set; }
public int? Year { get; private set; }
public void Update(string? arg_color = null, int? arg_year = null)
{
// Prevent assigning a combination of values that we know are wrong.
if (arg_color != "Black" && arg_year < 1910)
{
throw new InvalidOperationException("All cars before 1910 were black");
}
// Or else, assign the values.
Color = arg_color;
Year = arg_year;
}
}
You'll notice also that I've made the properties Color
and Year
into private set
. This is because we're using an Update method, so there's no point having set
available to publicly use. We have deliberately prevented anyone from directly setting those values, so that they are forced to use our Update
method. You now set the values like this:
myCar.Update("Blue", 2024);
myCar.Color = "Blue"; // <- this no longer works because we have a private setter. The compiler will not allow it.
Typically, you would either have an Update method, or you would have set
methods of your properties. There's no point mixing both, and it will confuse you (and other developers) because it makes it unclear whether they should choose Update
or set
.
set
approach.The second concept you've mixed up a bit is this:
public Car Update(string arg_color = null, int? arg_year = null)
{
Car newCar = new Car();
// ...snipped code for brevity...
return newCar;
}
What you're doing here is creating a totally new car object, and returning it. You're not modifing or updating the original car at all.
So, both the Update
method and the set
methods described above, are not altering your car. You're literally creating a new car. Not updating one. If you try this in your code, you'll see this happens:
Car thisCar = new Car() { Color = "Red", Year = 2024 };
thisCar.Update("Blue", 2000);
Console.WriteLine(thisCar.Year); // <- this will still be "2024"
Console.WriteLine(thisCar.Color); // <- this will still be "Red"
So it will look like nothing has changed. In reality, what you've done in Update
is create a totally new Car, without realising it, which has the new values. You could prove it by trying this:
Car thisCar = new Car() { Color = "Red", Year = 2024 };
Car newCar = thisCar.Update("Blue", 2000);
Console.WriteLine(thisCar.Year); // <- this will still be "2024"
Console.WriteLine(thisCar.Color); // <- this will still be "Red"
Console.WriteLine(newCar.Year); // <- this will be "2000"
Console.WriteLine(newCar.Color); // <- this will be "Blue"
This is an odd mix. You've got an Update method that doesn't actually update the object, and returns something new instead.
There is a valid coding pattern where you can change some data (like modifying the colour) but safely leaving the original data intact, and returning a new copy. In C# this is done with record
and it looks like this:
public record Car(string? color, int? year);
This is basically identical to your Car
class, but much shorter. It has two properties and (as you'll see next) a way to update it.
So now, to finally answer your question: here you can take a Car
, modify some properties using the with
keyword, and the other properties are all copied forward:
Car redCar = new Car("Red", 2024);
Car blueCar = redCar with { Color = "Blue" };
Console.WriteLine(redCar.Color); // <- this will still be Red
Console.WriteLine(blueCar); // <- this will now be Blue, but also 2024
Note if you want to do validation, like in my Update example earlier, then you can still add an Update method to the record. I won't put an example here, but you can do some reading around record
^1 and see how to do that.
Hope that helps.