+4  A: 

Well first off you don't need your test for car.RegNumber == 5 in the loop - you've already found the first car that match this criterion from your statement:

Car car = CarsForSale.Find(c => c.RegNumber == 5);

In fact your whole loop is redundant, you can just have:

if (car != null)
{
    car.Color = "Red";
}
else
{
    CarsForSale.Add(new Car(5, "Red"));
}

Unless you want to find all cars that have RegNumber equal to 5, in which case your first line is incorrect as that will only find the first car that matches the criteria. To find all the cars you want something along these lines:

var cars = CarsForSale.Where(c => c.RegNumber == 5);

foreach (Car car in cars)
{
    car.Color = "Red";
}

if (!car.Any())
{
    CarsForSale.Add(new Car(5, "Red"));
}

With your original code the compiler should have warned you that the redefinition of car in the loop would hide the original definition (the one I've quoted).

ChrisF
I don't think that's a Linq statement.
Dan Tao
@Dan - I meant Lambda ;)
ChrisF
car.Count() == 0 is horrible way to test for no elements because if collection is not an ICollection<T> it will have to loop through all elements. Use !car.Any() instead which just checks the first elements existence.
Bear Monkey
@mjf196 - thanks!
ChrisF
+2  A: 

Why are you re-iterating through the list when you already have a result?

This will achieve the same outcome:

Car car = CarsForSale.Find(c => c.RegNumber == 5);
if (car != null)
{
   car.Color = "Red";
}
else
{
   CarsForSale.Add(new Car(5, "Red"));
}
Save(CarsForSale);

The result from the Find method of CarsForSale, if it returns a result, will be a reference type, which means any changes to car will change the item in CarsForSale as well. I'm guessing you thought that the result from Find would be disconnected from the actual item in CarsForSale, hence the unnecessary foreach loop?

GenericTypeTea
Yes indeed I did and I hang my head in shame about it too...
Peter Kelly
+2  A: 

Once you have the car you're looking for from the LINQ statement, there's no need to loop back through the collection to find the match:

Car car = CarsForSale.Where(c => c.RegNumber == 5).FirstOrDefault();

if(car != null)
{
    car.Color = "Red";
}
else
{
    CarsForSale.Add(new Car(5, "Red"));
}

Save(CarsForSale);

Or if there are going to be multiple Cars with the same RegNumber:

var cars = CarsForSale.Where(c => c.RegNumber == 5);

if(cars.Any())
{
    foreach(Car car in cars)
        car.Color = "Red";
}
else
{
    CarsForSale.Add(new Car(5, "Red"));
}

Save(CarsForSale);
Justin Niessner
FirstOrDefault() will take the first match only. Find() will do the same thing.
Justin Niessner
Don't use Where followed by FirstOrDefault. FirstOrDefault has an overload that takes a filter. And anyways if CarsForSale is a List<Car>, using Find is better.
Trillian
@Trillian - Even though you can pass a Predicate to FirstOrDefault, I like to keep them separate to clearly state intent and make it easier to modify in the future (even if marginally so). The two get evaluated the same so there's no performance difference. Also, why would List.Find() be any better (especially given the fact that he might need multiple matches)?
Justin Niessner
@Justin Of course Find won't do if there are multiple matches. But for a single match, it is slightly better than FirstOrDefault because it's provided by the class itself and skips the overhead of using an enumerator. Ok, maybe I'm nitpicking :)
Trillian
@Trillian My point was more that Find() (more than likely, I can't check at the moment) uses an enumerator anyway so I still don't see the extra overhead.
Justin Niessner
+2  A: 

Update

In response to this comment you've left on a couple of other answers:

What if there are several cars with the RegNumber of 5?

If it's possible for multiple cars to have the same RegNumber, then calling Find is not the right approach. Find is just enumerating over the list to find a match; you'd be better off skipping it and keeping your foreach loop.

You could, however, make your code more concise by using Where instead:

var matches = CarsForSale.Where(c => c.RegNumber == 5);
int numMatches = 0;

foreach (Car match in matches )
{
    match.Color = "Red";
    ++numMatches;
}
if (numMatches == 0)
{
   CarsForSale.Add(new Car(5, "Red"));
}

Original answer

That whole foreach loop is redundant: you're basically doing the same work you already did by calling Find.

So the code can be simplified:

Car car = CarsForSale.Find(c => c.RegNumber == 5);

if (car != null)
{
    car.Color = "Red";
}
else
{
   CarsForSale.Add(new Car(5, "Red"));
}

That said, if you're looking up cars in your List<Car> by RegNumber, it would make sense to use a Dictionary<int, Car> instead of a List<Car>:

Car car;
if (CarsForSale.TryGetValue(5, out car))
{
    car.Color = "Red";
}
else
{
    CarsForSale[5] = car = new Car(5, "Red");
}
Dan Tao
+1  A: 

So as Dan already mentioned, if you have a unique property you should use it as a key within a Dictionary<TKey, TValue>.

Cause checking if something is within a Dictionary is an O(1) operation, while within a List it is just O(n) in the worst case (and now imagine you have 1 million cars within your list).

var carsForSale = new Dictionary<int, Car>();

//Create a car which you like to check
var checkCar = new Car(4, Color.Red);

//Use this approach if you want to change only a few properties
//of an existing item
if (carsForSale.ContainsKey(checkCar.RegNum))
{
    carsForSale[checkCar.RegNum].Color = checkCar.Color;
}
else
{
    carsForSale[4] = checkCar;
}

//If you have to take over ALL property settings, you can also
//forget the old item and take the new one.
//The index operator is smart enough to just add a new one
//or to delete an old and add the new in one step.
carsForSale[checkCar.RegNum] = checkCar;

Dummy implementation of the car class:

public class Car
{
    public int RegNum { get; private set; }
    public Color Color { get; set; }

    public Car(int regNum)
        : this(regNum, Color.Empty)
    { }

    public Car(int regNum, Color color)
    {
        RegNum = regNum;
        Color = color;
    }
}

The problem why you are using a Dictionary is, cause you want to explicitly tell what the key is (the RegNum property of your car), but you could also use a Hashset<T> if your Car object would correctly implement Equals() and GetHashCode() but this is a little more complex than you might think. A good explanation can be found in the Essentials C# book.

Oliver
Thanks Oliver, I take your point (and Dan's) on the Dictionary being more efficient. I hadn't thought of Hashset<T> so I'll look into that too and see if it applies in my case.
Peter Kelly
Yes, a HashSet would also work, if two items with the same RegNumber would reveal the same HashCode.
Oliver