It's not proper functional programming in the Haskell or CaML sense, no, because you've got mutable variables and stuff. Mostly it is just having first-class functions, and yes, that's done through delegates and generics which we had in C# 2.0, but the 3.0 compiler has got type inference and lambda syntax and pre-defined Action<T> and Func<T,TReturn> delegate classes and stuff which just make it all much easier to deal with.
For example, you use to have to say
list.Find(delegate(string s){ return s.StartsWith("A"); }
whereas now you can say
list.Find(s => s.StartsWith("A"));
which is much more readable.
Plus, using lambda expressions instead of delegates changes the way you think about them, makes them seem more like variables and things you can throw around the place and store in hash tables and so forth.