tags:

views:

206

answers:

6

I have code a bit like this

public class MyObject
{
    private bool IsValidDay(ref DateTime theDate)
    {

    ...
    }
}


MethodInfo[] methods = myObjectInstance.GetType().GetMethod("IsValidDay", BindingFlags.Instance | BindingFlags.NonPublic);
object[] args = { null };
bool val = (bool)method.Invoke(myObjectInstance, args);

But when the method is called, from within the IsValidDay method, theDate is DateTime.MinValue. This seems awfully weird - I'd perhaps expect a NullReferenceException to be thrown but not an automatic conversion.

In case you are wondering, this is code in a unit test. (in use the method is typically called via a public method that takes object).

As far as some other code which is subsequently called is concerned, DateTime.MinValue and null are not the same thing, so it's a little bit of a problem.

Any clues?? Suggestions.

+3  A: 

A DateTime variable can't be null. It's not a reference type, so there won't be a null reference exception.

You could do:

private bool IsValidDay(ref DateTime? theDate)
{
   if(theDate.HasValue)...
}

Here's a link talking about nullable types: http://msdn.microsoft.com/en-us/library/1t3y8s4s%28VS.80%29.aspx

I think I get what you are asking.... in the case of your code (especially because of the ref parameter, you can't have variance on a parameter with ref or out). It has to pass in a DateTime object. It can't be anything else.....so the null argument has to be converted to something to get the function to work.

Kevin
I know about nullable types, have used them in the past, and agree they are probably the tool for this job - unfortunately, I am maintaining /extending existing code which I can't change to a nullable type.
kpollock
+2  A: 

DateTime has a value, I suggest you use DateTime? (or Nullable<DataTime>) to support nulls

Brett Veenstra
see above comment
kpollock
A: 

Only reference types can be null. DateTime (like int, bool, structs, and enums) is a Value Type. Therefore DateTime cannot be null, just like an enum can't be null. You can use the Nullable generic, by declaring it as DateTime?. This will allow you to check it for null.

C. Ross
+3  A: 

From MSDN:

Any object in this array that is not explicitly initialized with a value will contain the default value for that object type. For reference-type elements, this value is null. For value-type elements, this value is 0, 0.0, or false, depending on the specific element type.

The default value of DateTime is DateTime.MinValue:

DateTime.MinValue == new DateTime() // true


This explains why DateTime.MinValue gets passed to the method when you call it with null.

Note that you cannot pass null to the method anyway when you call it without reflection:

DateTime dt = null; // cannot assign null to value type
obj.IsValidDay(ref dt);

So I'd say you don't need to test your method with a null reference.


If you want your method to accept null, you can change the declaration to DateTime? as others have already pointed out:

private bool IsValidDay(ref DateTime? dt) { ... }
dtb
For the nullable type suggestion see my comment above. In the calling unit test code the value is explicitly initialised to null - but it acting as you describe above nonetheless. I wll have to check the the actual production code - I thought the method may be called via reflection, but I am not sure - hill have to dig through our framework code to make sure it doesn't.
kpollock
+1  A: 

Invoke() method takes an array of values for the target method parameters. According to MSDN, uninitialized elements of this array corresponding to the ref parameters will be initialized with the default value (in this case DateTime.MinValue) before the target method call.

Also, the value in the parameters array corresponding to the ref parameter will be updated after the target method call.

In your case you shouldn't test the method with a null value because it's not a valid value for the DateTime data type.

This is a comment from Invoke method doc in MSDN library:

"If the method or constructor represented by this instance takes a ref parameter, no special attribute is required for that parameter in order to invoke the method or constructor using this function. Any object in this array that is not explicitly initialized with a value will contain the default value for that object type. For reference-type elements, this value is null. For value-type elements, this value is 0, 0.0, or false, depending on the specific element type."

Also found this tutorial: Passing "ref" Parameters

AlexD
as far as I know the only way to pass a ref parameter to Invoke is as I have done in my example code, which I came up with from the MSDN entry on ref parameters.
kpollock
Yep, it appears I didn't understand Invoke() call with ref parameters correctly. Fixing my response...
AlexD
A: 

In the end, in this case, I think I'll go with the notion that the method doesn't actually need to be tested vs null, and note to myself that invoking methods via reflection doesn't always throw an exception when a straight function call would.

Other people may find the nullable type suggestion useful (though I imagine everybody has conttoned onto these by now...)

kpollock