The things is, any heuristic that might sound plausible is probably not going to cut it. And when you're asking your compiler (build system) to produce an output you better damn guarantee that the output is what you expect it is.
As far as I know, MSBuild doesn't do this. It always rebuilds (from scratch) the entire solution/project. However, when MSBuild is being invoked from within Visual Studio temporary compilation units are maintained in the \obj folder of your project. Emptying that folder is the same as rebuilding.
That said if the compiler or build system was to reuse outputs it would use checksums of the actual file contents to determine whether a compiled output can be retrieved from some other place. This is basically the only reliable way you could determine whether a file actually needs to be recompiled from scratch. FYI, this is done by the Visual C# compiler not MSBuild.
The file system "last modified date" attribute wouldn't be consistent cross systems and therefore not ultimately used to determined whether to build with cached output or build from scratch.