Lamda expression Where VS FirstOrDefault

Viewed 199

I am new using lamda expressions and i am trying to figure some things. I have created the following part of code which code returns the file path of a log file.

public static string GetLogFile()
{
    var fileTarget = LogManager.Configuration.AllTargets.Where(t=>t.Name == "LogName") as FileTarget;            
    return fileTarget == null ? string.Empty : fileTarget.FileName.Render(new LogEventInfo { Level = LogLevel.Info });
}

My problem is that fileTarget is empty when i am using:

LogManager.Configuration.AllTargets.Where(t=>t.Name == "LogName")

But if i change that line of code as

LogManager.Configuration.AllTargets.FirstOrDefault(t=>t.Name == "LogName")

Returns the correct path for my log file. Can anyone explain to me if there is a major difference between Where and FirstOrDefault?

3 Answers

In your case, Where returns a IEnumerable (simply a list) of the object FileTarget. Then, you cast this list to FileTarget. That's why it's null.

But FirstOrDefault returns an object or null and is castable to your class FileTarget. That's why it works.

Where actually returns an IEnumerable (intellisense will tell you this). It doesnt know how many items your predicate might match. FirstOrDefault will get the first item, or the first item that matches your predicate. If you passed one.

(Nb. A predicate is any function that takes an object and returns a bool, there is a .Net type called Predicate<T> that represents it)

To tidy it all up and you could do this, using the OfType linq operator and null propagation and null coalescing operators

public static string GetLogFile()
{
    var fileTarget = LogManager.Configuration.AllTargets.OfType<FileTarget>().FirstOrDefault(t=>t.Name == "LogName");            
    return fileTarget?.FileName.Render(new LogEventInfo { Level = LogLevel.Info }) ?? string.Empty;
}

In simple words,

Where will provide you a Enumerable. Will not be null. Empty if there is no match in the predicate. FirstOrDefault will give you an object. Null if there is no match.

Going by your code, it should throw a compilation error saying it cannot convert from IEnumerable to FileTarget.

Related