2

I just saw some snippet code using the struct DateTime.Today and I can't understand the inner workings of it. Here is the specific line:

if (DateTime.Today.DayOfWeek == DayOfWeek.Monday)

After using Go To Definition F12, I saw that the Today static method returns a DateTime object with the date information in your current computer. I suppose that Today method works as a constructor wrapper. What I can't deduce (more like guessing) is how it's possible to access the property DayOfWeek without instantiating first the Today struct.

Can someone explain me how is this possible? My only guess is that when VS compiles the code to IL maybe it converts this syntactic sugar to:

if ( (DateTime.Today()).DayOfWeek == DayOfWeek.Monday )

Maybe this is as clean as water but I'm a C# newbie so I just can't figure it out.

Thanks in advance!

Alexander Bell
  • 7,842
  • 3
  • 26
  • 42
3rdWorldCitizen
  • 264
  • 2
  • 5

2 Answers2

2

Pertinent to your question, DateTime.Today is a Property type of DateTime, and as such it has DateTime.DayOfWeek Property as any regular DateTime structure.

In a broader sense regarding how do Properties work in C#: in a first approximation, just for better understanding you may think of Properties as Methods masqueraded to look like a field, so your interpretation of Today as some hypothetical GetToday() method is logically close, but not "academically precise" (see the comments by @CalebB).

I would recommend to familiarize yourself with .NET Properties (https://msdn.microsoft.com/en-us/library/x9fsa0sw.aspx) and DateTime Structure (https://msdn.microsoft.com/en-us/libraRy/system.datetime.aspx)

Hope this may help.

Alexander Bell
  • 7,842
  • 3
  • 26
  • 42
  • As I mention in @toby 's answer, thinking of a property as a method isn't quite right, a method is a form of delegate whereas a property is not. A property has a getter and/or setter which may or may not call an outside named method as shown in my comment on toby's answer. – CalebB Jun 28 '15 at 01:52
  • Indeed, this interpretation is not "academically precise" in general and as any analogy it may have some deficiency, but pertinent to this and many other cases it's a good logical simplification for the beginners helping to understand the otherwise kinda unclear issue. Best regards, – Alexander Bell Jun 28 '15 at 01:58
  • 1
    @AlexBell a property is just a method that the compiler generates for you it's perfectly correct if you take a look at the assembly code posted below you'll notice that there's basically no difference – Bobby Tables Jun 28 '15 at 02:53
1

You guest it right, welcome to the wonderful world of properties.

DateTime.Today is a property which in short is a function generated by the compiler, it translates to DateTime.get_today(). So that expression would actually be

if ( (DateTime.get_today()).DayOfWeek == DayOfWeek.Monday )

Example:

public class Test
{
    private string _lastName = "LName";
    private string _firstName = "FName";
    public string Name { get{
        return _lastName + " " + _firstName;
    } }

    public string GetName()
    {
        return _lastName + " " + _firstName;
    }
}
class Program
{
    static void Main(string[] args)
    {
        var test = new Test();
        Console.WriteLine(test.Name);
        Console.WriteLine(DateTime.Today.DayOfWeek);
    }
}

Decompiled GetName

.method public hidebysig instance string 
        GetName() cil managed
{
  // Code size       28 (0x1c)
  .maxstack  3
  .locals init ([0] string CS$1$0000)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldfld      string ConsoleApplication1.Test::_lastName
  IL_0007:  ldstr      " "
  IL_000c:  ldarg.0
  IL_000d:  ldfld      string ConsoleApplication1.Test::_firstName
  IL_0012:  call       string [mscorlib]System.String::Concat(string,
                                                              string,
                                                              string)
  IL_0017:  stloc.0
  IL_0018:  br.s       IL_001a
  IL_001a:  ldloc.0
  IL_001b:  ret
} // end of method Test::GetName

Decompiled Name

.method public hidebysig specialname instance string 
        get_Name() cil managed
{
  // Code size       28 (0x1c)
  .maxstack  3
  .locals init ([0] string CS$1$0000)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldfld      string ConsoleApplication1.Test::_lastName
  IL_0007:  ldstr      " "
  IL_000c:  ldarg.0
  IL_000d:  ldfld      string ConsoleApplication1.Test::_firstName
  IL_0012:  call       string [mscorlib]System.String::Concat(string,
                                                              string,
                                                              string)
  IL_0017:  stloc.0
  IL_0018:  br.s       IL_001a
  IL_001a:  ldloc.0
  IL_001b:  ret
} // end of method Test::get_Name

Decompile Main(method calls)

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       56 (0x38)
  .maxstack  1
  .locals init ([0] class ConsoleApplication1.Test test,
           [1] valuetype [mscorlib]System.DateTime CS$0$0000)
  IL_0000:  nop
  IL_0001:  newobj     instance void ConsoleApplication1.Test::.ctor()
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  callvirt   instance string ConsoleApplication1.Test::get_Name() //here
  IL_000d:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0012:  nop
  IL_0013:  ldloc.0
  IL_0014:  callvirt   instance string ConsoleApplication1.Test::GetName()//here
  IL_0019:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_001e:  nop
  IL_001f:  call       valuetype [mscorlib]System.DateTime [mscorlib]System.DateTime::get_Today()//here
  IL_0024:  stloc.1
  IL_0025:  ldloca.s   CS$0$0000
  IL_0027:  call       instance valuetype [mscorlib]System.DayOfWeek [mscorlib]System.DateTime::get_DayOfWeek()
  IL_002c:  box        [mscorlib]System.DayOfWeek
  IL_0031:  call       void [mscorlib]System.Console::WriteLine(object)
  IL_0036:  nop
  IL_0037:  ret
} // end of method Program::Main

As you can see there is absolutely no difference between Name and GetName except the fact that Name is generated by the compiler for you as get_Name.

Update 1

As for DateTime.Today it actually get transformed into

System.DateTime [mscorlib]System.DateTime::get_Today()

What you have to understand is that even if the compiler generates those functions for you, they can't be accessed directly because it generates IL code(assembly code for .NET) not C# (things might have changed with Roslyn the new C# compiler but don't know much about that)

What i recommend, if you're really curious about what really happens in you application, is to use ildasm.exe it allows you to see the IL generated by the compiler. A nice book on the subject it called CLR via C#, i had contact with the 3rd edition but apparently there's a 4th edition now.

Bobby Tables
  • 2,953
  • 7
  • 29
  • 53
  • I think it's worth mentioning getters and setters in this case, the getter in this case calls and returns the return value of the GetToday method but it doesn't have to resolve to calling another named method. Example: `string FullName { get { return first + " " + last; } }` – CalebB Jun 28 '15 at 01:49
  • @CalebB i'm sorry but i don't get you're point. There is no `Today`, the same as there is no `FullName`, these two properties are just syntactic sugar an easier way to call the `GetFullName()` and `GetToday()` methods. `Today` is not calling `GetToday`, `Today` is `GetToday()` – Bobby Tables Jun 28 '15 at 02:00
  • You're description is flawed though, Today is a property that "get's" today but is not a delegate defined as "GetToday()" it is very misleading even if it "seems" to have the same outcome. A way to look at it is GetToday is a delegate object that is invoked whereas Today is a property where Today.GetValue() is invoked and returns a value from your get statement. Take a look at your link. – CalebB Jun 28 '15 at 02:05
  • @downvoter care to explain ? – Bobby Tables Jun 28 '15 at 02:44
  • @CalebB i reiterate a property is just a function that the compiler generates for you and that's it, nothing more, i never said anything about delegates i just said it's syntactic sugar. The only thing incorrect about the answer is that it's get_Today not GetToday(). Posted the dissembled code. – Bobby Tables Jun 28 '15 at 02:47
  • @toby thanks for the answer! Now I'm just wondering how the get accessor actually gets the job done. With your explanation I suppose that the code may look something like this: `return new DateTime("Default", "Date", "Values");`. I really want to understand it, even if is just syntactic sugar, because is a clean approach for chaining statements. It just looks nice! – 3rdWorldCitizen Jun 28 '15 at 16:13
  • @3rdWorldCitizen i updated my answer, as i said in it if you're really interested in what happens behind the scenes use ILdasm.exe, create a simple console application and look at the assembly code. – Bobby Tables Jun 28 '15 at 17:48