Targetting the runtime means compiling for the runtime, that is, among other things, outputting CIL aka MSIL (as opposed to x86/x64/etc. machine code).
Saying that anything that doesn't target the runtime is "unmanaged code", is a bit of a false dichotomy. Code running on the JVM for example is arguably managed, but I think we can take in this context the sentence to mean "unamanged [by the CLR]".
It would be possible to write a C# compiler that could spit out native code and not target the runtime (albeit you'd probably need some runtime for GC at least), and it is equally possible to write C compiler that spat out CIL. In this example the hypothetical C# compiler wouldn't be targetting the runtime but the hypothetical C compiler would be. The important distinction here is separating the language from its target.
A .NET application that didn't target the runtime would be a contradiction. If it didn't target the runtime it wouldn't be a .NET application.
It can get fuzzier though, with unsafe
and P/Invoke
. When you use functionality like P/Invoke
or COM interop, you end up targeting the runtime and additionally some other stuff. This doesn't mean you've stopped targeting the runtime though, it just means you have additional dependencies beyond the runtime. Keeping track of this sort of stuff is why things like the CLSCompliantAttribute
exist.