This is a moot point for pure C# apps, but what if you're writing in MC++ (or some other 'mixed' language) and you want to know if a function is getting compiled as managed or native code?
You can try and inspect the source and infer from the language rules. Eg, in MC++, look for #pragma managed / #pragma unmanaged. However, that's risky because maybe there's some language rule that you're not aware of. (Pop quiz: Do you know all the rules that will cause MC++ to compile a function into native code instead of IL?)
So if you want more paranoid verification...
VS shows managed debugging disassembly starting with offset 0, eg:
int main(array<System::String ^> ^args)
00000000 push edi
00000001 push esi
00000002 push ebx
Whereas native disassembly is shown with absolute addresses:
int Add(int a, int b)
00401000 push ebp
00401001 mov ebp,esp
return a + b;
00401003 mov eax,dword ptr [a]
00401006 add eax,dword ptr [b]
This is clearly a heuristic since it's just a behavior-specific aspect of VS. The CLR Debugging services provides the actual address of jitted code, so VS could show both manage and native disassembly the same. However, the stackwalking APIs are 100% clear about whether code is managed or native, so a debugger tool can also pass that information onto the user.