Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic does not respect return type

Tags:

c#

I am pretty new to C# dynamic keyword. In one of my projects I tried to play with it and encountered some unexpected behavior. I managed to reproduce the situation with the following code:

class Program
{
    static DateTime? DateOnly(DateTime? time)
    {
        return time.HasValue ? (System.DateTime?)time.Value.Date : null;
    }

    static void Main(string[] args)
    {
        dynamic now = System.DateTime.Now;
        var date = DateOnly(now);
        Console.WriteLine(date.Value); // error thrown here
        Console.Read();
    }
}

I get a RuntimeBinderException saying

'System.DateTime' does not contain a definition for 'Value'.

So the variable date is treated as DateTime instead of DateTime?.

It looks like dynamic somehow ignores the return type declaration. Should I avoid using var with dynamic?

like image 712
Siu Pang Tommy Choi Avatar asked Jan 12 '16 23:01

Siu Pang Tommy Choi


2 Answers

Because you pass a dynamic variable to the DateOnly method, the return type also becomes dynamic. So in this case, your var date is actually dynamic date. It contains a boxed nullable DateTime, but boxing doesn't preserve the "nullable" part, so in fact it's just a boxed DateTime, which doesn't have a Value property. So you should just do Console.WriteLine(date) to print the value.

As you can see, nullable types and dynamic don't play very well together...

like image 64
Thomas Levesque Avatar answered Oct 19 '22 22:10

Thomas Levesque


There are two issues. One is that date is still dynamic because the right hand side is a dynamic expression. If you had declared date with the specific type DateTime? you would not see this. The other issue is that you are returning a nullable value type and conversion to dynamic is considered boxing. Nullable value types are never boxed as such. The underlying value type is unwrapped so date behaves more like a reference of type object that can either have a DateTime or can be null, not a reference to a DateTime?. The binder then tries to resolve the property Value against DateTime and fails. If you try Console.WriteLine(date), however it will fail as ambiguous because that method has so many overloads. So you will have to do something like Console.WriteLine((object)date), at which point you might as well declare date as object for this simple example.

like image 21
Mike Zboray Avatar answered Oct 19 '22 22:10

Mike Zboray