Reputation: 59
So I am learning more C# and came across this syntax:
Log.Info(() => $"Some Text {SomeVariableorProperty}");
How does this differ from the following?
Log.Info($"Some Text {SomeVariableorProperty}");
I know that the () => is basically a delegate but not sure what its purpose is here.
Upvotes: 4
Views: 192
Reputation: 111870
The scenario is:
Log.Info(() => $"Some Text {SomeSlowMethod()}");
public static string SomeSlowMethod()
{
Thread.Sleep(5000);
return "Foo";
}
Now... What happens if the logging of Info
is disabled? Is the SomeSlowMethod
called? The answer is no! Because the calling of the delegate () => $"Some Text {SomeSlowMethod()}
is done by Log.Info()
if it needs to do it. Compare it with:
Log.Info($"Some Text {SomeSlowMethod()}");
Now SomeSlowMethod()
is always called, and there is the possibility that Log.Info
will ignore its value.
If you think that SomeSlowMethod()
s in real case scenarios don't exist, remember that even string composition is "slow" compared to other operations. Simply doing useless string.Format
($"Some Text {SomeVariableorProperty}
is a string.Format
) is a waste of time. And one of the laws of a good logging library is that if it isn't active it shouldn't slow your application.
To make an interesting comparison, Debug.Assert()
:
[Conditional("DEBUG")]
public static void Assert(bool condition, string message);
Here message
is a string
, but you see the [Conditional(...)]
? if DEBUG
isn't defined at compile time, the C# compiler can remove the whole Debug.Assert()
method call, and even remove all the methods that are called inside the Debug.Assert()
, so modifying possible side effects:
Debug.Assert(false, Throw());
public static string Throw()
{
throw new Exception();
}
If DEBUG
isn't defined (so you are executing a RELEASE
build), this will be converted to:
; // nothing
so no throw
(see for example this). But note that this must be resolved at compilation time, while logging libraries are configured at runtime.
Upvotes: 19
Reputation: 34489
It means that the Log.Info
method is expecting a function with the signature Func<String>
, essentially a parameterless function that will return a string.
Passing $"Some Text {SomeVariableorProperty}"
directly will fail when building, as this is a String
and not a function that can be executed. That is - unless the method itself has overloads that accept just a String
.
If you're in complete control over the code, then completely agree that it's a little odd, I can't see a strong reason for wanting to use a function over a String
.
The only good use case for this as @KirkLarkin suggests is if the generation of that Log message needs to be done in a lazy manner. You'd probably only need this in an edge case scenario where the creating the actual message to log is an expensive operation. That way if you're call to Log.Info()
decides it doesn't need to log it (e.g. it's too verbose based on a setting) you can bypass the expensive message generation. As I say though - it'd be rare that you'd come across a situation like this and probably indicates that too much is being logged.
Upvotes: 5