I came across the accepted answer of this question about dealing with DateTime.Now in unit tests which contains the following code example:
private readonly Func<DateTime> _nowProvider;
public SomeClass(Func<DateTime> nowProvider)
{
_nowProvider = nowProvider;
}
public bool Foo()
{
return (_nowProvider().DayOfWeek == DayOfWeek.Sunday);
}
Instantiated as such:
var s = new SomeClass(() => DateTime.Now);
I've not much used Func<T>
in C# so I thought I'd take a look at the Microsoft documentation for it which has the following remarks:
You can use this delegate to represent a method that can be passed as a parameter without explicitly declaring a custom delegate. The encapsulated method must correspond to the method signature that is defined by this delegate. This means that the encapsulated method must have no parameters and must return a value.
Why would it be more beneficial in the example to pass a Func<DateTime>
, instantiated as Class(() => DateTime.Now)
to the constructor
Rather than to just simply pass in a DateTime
parameter instantiated as Class(DateTime.Now)
to the constructor?
According to the Microsoft documentation mentioned above LINQ lambda constructors also take Func<T>
arguments and my experience with these proves they are extremely flexible but I can't understand why?
Rather than to just simply pass in a DateTime parameter instantiated as Class(DateTime.Now) to the constructor?
Because the value should be the current DateTime and not the one when the class has been instanciated.
When the code runs, the Func returns the Date of exactly when the code is executed.
If the DateTime would be stored in a field, it would be the time of creation, not now.
I have an example.
Let's say you create an instance of Class
at 23:59:55 on Saturday.
10 Seconds later, the following snipped:
(passedDateTime.DayOfWeek == DayOfWeek.Sunday);
would return false.
With the provider, the datetime is actually on sunday - the time it is executed at.
Technical:
DateTime is a struct.
When passing DateTime to a method or constructor as a parameter, it is passed as a value, not a reference.
Thus the DateTime
will not be up to date, but just a snapshot of the value.
You can confirm this yourself:
var dateTime = DateTime.Now;
System.Threading.Sleep(1000);
bool equals = dateTime == DateTime.Now; // false
This pattern allows the Date and Time to be provided either by DateTime.Now
, during normal operation, or to be closely controlled during unit testing.
For example, a Unit Test that wants to test time based functionality could verify that the returned result is correct when a function is called twice with more than 5 minutes between each call (a common caching technique), without having to wait 5 minutes between calls.
It is also an example of the "Inversion of Control" pattern. Where a method of retrieving data is "injected" in to the class, usually via constructor. The class is then free to use whatever method was injected without being aware of its implementation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With