It's got some other nice syntactic sugar, like checked exceptions and XML literals. Nothing game-changing, but stuff I do occasionally miss when working in C#.
It used to be that VB.NET's late binding features made interacting with COM objects way easier, but C# sorted that out when `dynamic` came along.
Now the only difference that I'd say is really substantive is C#'s unsafe blocks. However, I should immediately follow that up by saying that in the past 5 years I think I've written a grand total of one unsafe block that turned out to be a keeper, and the only reason I'm not embarrassed to admit that I even bother with unsafe blocks is that I have no shame.
I think C# 6 has exception filters; interesting that they took so long. VB was also on the right-ish track with optional parameters. It's hilarious, in hindsight, how terribly wrong the C# design was on that feature. And C# still got it wrong by not providing a way to indicate the lack of value, instead of compiling a default into the callsite.
It used to be that VB.NET's late binding features made interacting with COM objects way easier, but C# sorted that out when `dynamic` came along.
Now the only difference that I'd say is really substantive is C#'s unsafe blocks. However, I should immediately follow that up by saying that in the past 5 years I think I've written a grand total of one unsafe block that turned out to be a keeper, and the only reason I'm not embarrassed to admit that I even bother with unsafe blocks is that I have no shame.