Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why pass func<T> to constructor rather than T?

Tags:

c#

linq

func

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?

like image 924
Danny Lager Avatar asked Dec 18 '22 05:12

Danny Lager


2 Answers

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
like image 138
Mafii Avatar answered Dec 31 '22 21:12

Mafii


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.

like image 45
Bradley Uffner Avatar answered Dec 31 '22 20:12

Bradley Uffner