Why pass func<T> to constructor rather than T? - c#

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.

I attach a small example on how this could look like in a unit test.
If you would not have the ability to provide a different "Now" the unit test will behave different depending on the time it runs.
[TestMethod]
public void TestFoo()
{
var obj = new SomeClass(() => DateTime.Now);
//Only true on sundays
Assert.IsTrue(obj.Foo());
//This is sunday
obj = new SomeClass(() => new DateTime(2017, 7, 30));
//This will be always true
Assert.IsTrue(obj.Foo());
//This is not sunday
obj = new SomeClass(() => new DateTime(2017, 7, 29));
//This will be always false
Assert.IsFalse(obj.Foo());
}

Related

parameter order independent function call

is there a way to implement below scenario of function as a single call, so that for caller it looks like singe call (If not i can declare them as 2 overloaded calls, but checking if language has some feature)
Add(int, dateTime)
Add(datetime, int)
so that caller can call Add(2, DateTime.Now) Or Add(DateTime.Now, 2).
My scenario is that arguments to pass will come in an array, and i want caller can just call Add(args[0], args[1])
I can't use parameter name here as any parameter can be of any type. basically i want to have equivalent of
DateTime + int
int + dateTime
I would recommend just picking the order of arguments that makes sense to you, and sticking with that. Having multiple overloads of the exact same argument list in different orders is non-conventional and potentially confusing to consumers of your API.
One thing that can be done when calling methods is using Named Arguments. If your consumers use named arguments, they can put them in whatever order they want.
For example:
public static DateTime Add(int daysToAdd, DateTime date)
{
return date.AddDays(daysToAdd);
}
private static void Main()
{
// Call the method passing the int first, then the DateTime
var newDate1 = Add(daysToAdd: 5, date: DateTime.Now);
// Call the method passing the DateTime first, then the int
var newDate2 = Add(date: DateTime.Now, daysToAdd: 5);
}
No, there is no specific language feature for that.
In such cases you could use params object[] to give 0 or more parameters to the method, but I highly doubt that will ever give a decent working piece of code with is not error-prone. It means you have to cast every parameter to the desired type when you want to use them as such.
If you the types are hard-coded on the calling side, it is better to keep 1 single method.
define one of them, for exemple:
Add(int offSet, DateTime dataTime)
then use it like this
Add(offSet:2,dataTime:DateTime.Now)
Add(dataTime:DateTime.Now,offSet:2)
you can as well create a new method:
Add(DateTime dateTime, int offSet){
Add(offSet,dateTime );
}

DateTime.Now in class constructor

Good day all.
I am working on something that handles tasks.
Each task consists of 3 strings and a DateTime Object
Below is the constructor I built.
public Task(string von, string was, string an, DateTime zeit = DateTime.Now)
When compiling I get compiler error
Default parameter value for 'zeit' must be a compile-time constant (CS1736)
I assume the problem is, that -obvioulsy- the value for DateTime.Now depends on the time the constructor is called, which is the whole point that I want to have here.
I already looked at [this] thread, but it does not really apply to me, because the memory demand for a DateTime Object is always the same and that thread says the problem is the unknown heap-demand of that call.1
I already have an idea for a work-around (see below), but as we all know work-arounds are not best practice
public Task(string von, string was, string an, DateTime zeit){
if(zeit == null)
dateOfCreation = DateTime.Now; //dateOfCreation being the name of Task's internal DateTime field.
else
dateOfCretion = zeit;
So if I want to use the current DateTime I pass null. However: If I take the time and effort to always specifically pass null, I might as well each time pass DateTime.Now.
Question:
Is there a way to get parameter DateTime zeit = DateTime.Now accepted or substituted with identical outcome?
Use Constructor overloading instead:
public Task(string von, string was, string an, DateTime zeit)
{
...
}
public Task(string von, string was, string an) : this(von, was, an, DateTime.Now)
{
...
}

C# class design with multiple parameters

I have a repository class that I want to add two methods to:
public IEnumerable<OpenCall> OpenCalls()
{
return something;
}
public IEnumerable<OpenCall> OpenCalls(DateTime start, DateTime endd)
{
return something_slightly_different;
}
Inside each method I am going to call another method (AverageResolutions()) that returns a list of average resolutions. Obviously this method will also need to take 0 parameters or 2 parameters. The way I'm doing things at the moment I'm either going to end with two almost identical copies of OpenCalls(), or two almost identical copies of AverageResolutions(), altered slightly to allow for the DateTime parameters.
I think I'm doing this wrong - how can I just end up with one version of a method that will either take 0 or 2 parameters and then decide what to call further down the line if they are either null or not null?
You could change the method signature to use optional arguments:
public IEnumerable<OpenCall> OpenCalls(DateTime? start=null, DateTime? end=null)
{
if (start.HasValue && end.HasValue)
{
return something_slightly_different;
}
return something;
}
Note that you will need to make the DateTime-parameters nullable, because otherwise you wouldn't be able to set default values (which have to be compile-time constants).
For more information about nullable types, and the syntactic sugar (writing DateTime? instead of Nullable<DateTime> see the MSDN article on Nullable Types
For more information about optional parameters see the Optional Arguments section of the MSDN article about Named and Optional Arguments.
public IEnumerable<OpenCall> OpenCalls()
{
return OpenCalls(null, null);
}
public IEnumerable<OpenCall> OpenCalls(DateTime? start, DateTime? endd)
{
//if (!start.HasValue) ... etc.
return something_slightly_different;
}
If this solution is "clever" really depends on your other code. Having dozens of null checks isn´t nice. If you only have to check once or twice, it may be a good solution.
Also, you could use optional parameters.

Overriding DateTime.MinValue causing issue

We are trying to override the DateTime.MinValue in our application, but by doing it we noticed that our Web services are timing-out, following is a sample code. Not sure what is wrong/what we are missing.
public MainWindow()
{
//Introducing this.. Causes timeout of the webservice call...
typeof(DateTime).GetField("MinValue").SetValue(typeof(DateTime),new DateTime(1900, 1, 1));
var yesitworks= DateTime.MinValue;
InitializeComponent();
ServiceReference1.Service1Client client = new ServiceReference1.Service1Client();
//Below call will timeout...
var value =client.GetData(10);
}
PS: This might not be the best solution for what we are trying resolve but now its more of curiosity as to why it is not working? how is it related.
DateTime.MinValue is a static readonly field. That means that library authors will not expect it to change, and may write code that depends on it having the expected value.
Hence, you should not change the value of DateTime.MinValue.
For example, a library may use it as the default value for a variable:
private mostRecentDate= DateTime.MinValue;
foreach (var date in myDates)
{
if (date > mostRecentDate)
{
mostRecentDate= date;
}
}
// Do something with the most recent date in myDates...
In this example, if myDates only contained dates earlier than your new value for DateTime.MinValue, then this code would set mostRecentDate to DateTime.MinValue rather than the latest date in myDates.
While this rather contrived example may not be good programming practise (for example, you could use Nullable instead), it is valid code, whose behaviour would be changed if you changed the value of DateTime.MinValue.
The point is that libraries you are using could also be dependant on the value on DateTime.MinValue, so changing it could break them. You are llucky in so far as you found out that this introduced a bug early. If you are unlucky, you would not see a problem until your software had gone live and some corner case was hit.
I had a similar problem recently.
You didn't tell why you wanted to override DateTime.MinValue, but I guess the reason is similar to mine:
I have a server written in .NET, which has .NET clients and (via COM-Interop) MS Access clients.
The clients pass DateTime values, and the server needs to check whether they passed a "real" value or DateTime.MinValue.
My problem was:
.NET's DateTime.MinValue is January 1st of the year 1
The smallest possible value for VBA's Date type is January 1st of the year 100
⇒ Checking for DateTime.MinValue didn't work when the data was coming from MS Access, because Date variables in Access can't hold a date as small as .NET's DateTime.MinValue.
At that point I tried to override DateTime.MinValue too, and found out it doesn't work.
My solution was to write an extension method for DateTime:
public static class DateTimeExtensions
{
public static bool MinValue(this DateTime input)
{
// check the min values of .NET *and* VBA
if (input == DateTime.MinValue || input == new DateTime(100, 1, 1))
{
return true;
}
return false;
}
}
For the code in your question, it would need to look like this:
public static class DateTimeExtensions
{
public static bool MinValue(this DateTime input)
{
if (input == new DateTime(1900, 1, 1))
{
return true;
}
return false;
}
}
Usage:
DateTime theDate = DateTime.Now;
// vanilla .NET
bool isMin1 = (theDate == DateTime.MinValue);
// with the extension method
bool isMin2 = theDate.MinValue();
I don't think you will be able to change the DateTime MinValue as it is read only, But if you can DON'T
DateTime:
public struct DateTime : IComparable, IFormattable, IConvertible, ISerializable, IComparable<DateTime>, IEquatable<DateTime>
{
public static readonly DateTime MaxValue
public static readonly DateTime MinValue
....

Rhino Mocks - mocking a method whose return value changes (even when passed the same parameter) with multiple calls

I'm looking to find out how I can mock a method that returns a different value the second time it is called to the first time. For example, something like this:
public interface IApplicationLifetime
{
int SecondsSinceStarted {get;}
}
[Test]
public void Expected_mock_behaviour()
{
IApplicationLifetime mock = MockRepository.GenerateMock<IApplicationLifetime>();
mock.Expect(m=>m.SecondsSinceStarted).Return(1).Repeat.Once();
mock.Expect(m=>m.SecondsSinceStarted).Return(2).Repeat.Once();
Assert.AreEqual(1, mock.SecondsSinceStarted);
Assert.AreEqual(2, mock.SecondsSinceStarted);
}
Is there anything that makes this possible? Besides implementing a sub for the getter that implements a state machine?
You can intercept return values with the .WhenCalled method. Note that you still need to provide a value via the .Return method, however Rhino will simply ignore it if ReturnValue is altered from the method invocation:
int invocationsCounter = 1;
const int IgnoredReturnValue = 10;
mock.Expect(m => m.SecondsSinceLifetime)
.WhenCalled(mi => mi.ReturnValue = invocationsCounter++)
.Return(IgnoredReturnValue);
Assert.That(mock.SecondsSinceLifetime, Is.EqualTo(1));
Assert.That(mock.SecondsSinceLifetime, Is.EqualTo(2));
Digging around a bit more, it seems that .Repeat.Once() does indeed work in this case and can be used to achieve the same result:
mock.Expect(m => m.SecondsSinceStarted).Return(1).Repeat.Once();
mock.Expect(m => m.SecondsSinceStarted).Return(2).Repeat.Once();
mock.Expect(m => m.SecondsSinceStarted).Return(3).Repeat.Once();
Will return 1, 2, 3 on consecutive calls.
Simply use
mock.Expect(m=>m.SecondsSinceStarted).Return(1).Repeat.Once();
mock.Expect(m=>m.SecondsSinceStarted).Return(2).Repeat.Once();
This will return 1 during the first call, and 2 during the second call. At least in Rhino Mocks 3.6.0.0.
If time is the determining factor in what the method returns, I would try to abstract out the time passage so you have direct control over it in your tests.
Something like an interface called ITimeProvider with a member called GetElapsedTime() and then create a default implementation to use throughout your application.
Then when you are testing, pass in a mocked ITimeProvider so you control what is perceived by your application to be time passed.

Categories

Resources