Can I use C# 4.0 with the target framework set to .NET 3.5 to develop an extension for ArcMap 9.3? Or does it have to be C# 3.0 or earlier?
Short answer: In my experience, there should be absolutely no problem developing .NET 3.5-based code for ArcGIS 9.3 in Visual Studio 2010 (with C# language version 4), as long as you explicitly target the .NET Framework 3.5. The C# language version is mostly irrelevant here.
P.S.: This answer does not go into the differences that exist between developing an ArcGIS extension for versions 9.3 and 10. (ESRI has made quite a few major changes to the add-in model, but I'm assuming you're aware of that.)
Longer answer: You need to distinguish between the C# language version, and the targeted Framework version.
You can think of the .NET Framework as being made up of two major parts: the CLR (Common Language Runtime), and the BCL (Base Class Library). The former is the "virtual machine", while the latter is the class library (containing all the types that you can look up on MSDN).
.NET Frameworks 2 until 3.5 all use the same CLR (version 2), that is, the execution environment hasn't really evolved. What has evolved, however, is the BCL. If you're running a .NET 3.5 application on a .NET 2 machine, the main problem will not be that the "bytecode" (CIL) will be incompatible (it won't), but that the application might refer to and use types that were not yet available in the .NET 2 BCL.
Now, when you tell Visual Studio 2010 to target the .NET Framework 3.5, it will make sure that you won't use BCL types from any later Framework version. It will also make sure that the code output by the C# compiler will not require features only available in the CLR version 4.
The C# language version has very little to do with all this. What the C# compiler really does it to take your source code and translate it to a much lower-level programming language called CIL (Common Intermediate Language). Certain C# language constructs will no longer be recognisable in CIL: For example,
yield return and
yield break do not exist in CIL. They are simply translated to implementations the
To sum this up: The C# language version becomes irrelevant as soon as your code is compiled. What is important is...
whether the output CIL/"bytecode" is compatible with the targeted .NET Framework (if you target .NET 3.5, it will be compatible even with .NET 2 for the reasons mentioned above); and
whether your code refers to / makes use of types that are available in the target framework.
One notable exception (in the sense that a C# language construct requires a particular version of the framework; this was last the case whwn generics were introduced IIRC) might be the C# keyword
dynamic. It might be compiled to code that requires types from the
System.Dynamic namespace, which is only available since .NET 4. But don't worry: If you've set up your Visual Studio 2010 project to target the .NET 3.5, you should get a compiler error if you're trying to use stuff that is not available, or compatible with, that particular .NET Framework version.