Any product or framework evolves. Mainly it's done to catch up the needs of it's users, leverage new computing powers and simply make it better. Sometimes the primary design goal also changes with the product. C# or .net framework is no exception. As we see, the present day 4th version is very much different comparing with the first one. But thing comes as a barricade to this evolution- backward compatibility.

In most of frameworks/products there are features would have been cut off if there was no need to support backward compatibility. According to you, what are these features in C#/.net?

Please mention one feature per answer.

  • Keyword new – Nemanja Trifunovic Mar 3 '11 at 20:19
  • 4
    The question is clearly not constructive according to the guidelines, and clearly constructive based on the fantastic answers. Voting to re-open. – psr Oct 27 '11 at 23:11
  • 1
    shame it closed, still maybe Eric will blog this instead of answering here? – jk. Oct 28 '11 at 14:29

13 Answers 13


Anonymous methods. I think everyone agrees that the anonymous method syntax chosen for C# 2.0 is chunky and clunky compared to the lambda syntax we added to C# 3.0. It is deeply unfortunate to have two almost-identical syntaxes to do the same thing.

  • 1
    Agreed, anonymous methods were great when we didn't have lambdas...now they're just redundant. – Michael Brown Jan 28 '11 at 18:56
  • 9
    There is one special feature of anonymous methods thats far better than lambda expressions .... their perfect name !! – explorest Jan 28 '11 at 19:36
  • 1
    At this point, I don't even remember the syntax for an anonymous method in C#. I'd have to look it up if for some bizarre reason I needed to use one instead of a lambda. – Kyralessa Oct 10 '19 at 14:07

I'd get rid of the Non-generic collections. They are an abomination...and there are too many cases where I'm using linq and have to do something like

var customObjects = container.CustomObjects.Cast<CustomObject>();

Every time I have to do that, a small part of my soul dies.

  • This is too great. – user2528 Jan 27 '11 at 4:47
  • 1
    Not all ports of .NET support Generics. .NET Micro is an example. May not apply if CustomObjects will never move to this platform. – goodguys_activate Jan 28 '11 at 16:23
  • 2
    That's the advantage to not having a soul. – CaffGeek Oct 27 '11 at 20:43

void as a type. Why on earth is "void" a type? It has no instances, it has no values, you can't use it as a generic type argument, formal parameter type, local type, field type or property type. It has no meaning as a type; rather, it is a fact about what effect a method call has on the stack of the virtual machine. But the virtual machine is just that: a virtual machine. The real machine will put the returned value in a register (typically EAX on x86) and not affect the stack at all! Void as a type is just a bad idea all around.

Worse: when used in a pointer type as in void* it means something completely different than what it means when used as a return type. Now it means "a pointer to a storage location of unknown type", which has nothing whatsoever to do with its meaning as "a method that doesn't return any value."

We can replace void* as a pointer type with IntPtr. (And void** with IntPtr* and so on.) We can replace void as a return type with "Unit", a type that has a single value, namely, null. An implementation of the CLR could then decide that a unit-typed function call could optimize its usage of registers or stacks appropriately, knowing that the null that is being "returned" can be safely ignored.

In such a world you no longer need separate Func<A, R> and Action<T> delegates. Action<T> is just Func<T, Unit>.

  • 4
    ... and Task is just a Task<Unit>. Reimplementing the library bits of the async CTP made me really wish for this... – Jon Skeet Oct 27 '11 at 19:24

The empty statement ;. Error-prone, almost always a typo, and gives you no added meaning that is not already expressed by {}.

  • 7
    Not to mention the huge performance penalty under the 64-bit JIT </snark>. – Jesse C. Slicer Jan 28 '11 at 19:43
  • 7
    An empty statement has a performance penalty? Why is that? – quentin-starin Oct 27 '11 at 20:07

Unsafe covariance on arrays of reference type. With typesafe covariance on IEnumerable<T>, at least some of the need for array covariance has gone away. (If we had a covariant read-only list interface then we wouldn't need it at all.)

  • I was absolutely going to write this down when I saw the question title -- you beat me to it :( – Chris Smith Jan 28 '11 at 16:24
  • 1
    The ability to receive a covariant array reference and safely write to the array references that were read from it is useful. If like IList<T> inherited from IReadableList<out T> and a non-generic IPemutable, it could support things like sorting, but arrays support it more easily. – supercat Mar 12 '14 at 6:52

The unary plus operator. Least useful operator of all time. If we didn't have to keep it for backwards compat, I'd take it out in a heartbeat. Who uses this thing, anyone?

(Clarification: The unary plus operator +x is not the preincrement operator ++x, not the postincrement operator x++ and not the binary addition operator x+y.)

  • 1
    for (int i=0;i<ceiling;i++) – Michael Brown Jan 28 '11 at 19:02
  • 13
    He's not talking about the preincrement and postincrement operators: he's talking about the unary plus, the opposite of the negative sign on a number: +1 == 1. It's pretty darn close to a no-op. – Jesse C. Slicer Jan 28 '11 at 19:31
  • 8
    It's not just about the effect on the machine readable output, it can improve the look of code for humans: if(a == +1 || a == -1){...}. – Thomas Bratt Feb 5 '11 at 13:26
  • 5
    @ShuggyCoUK: What is particularly bizarre about it is that it is overloadable. Because that happens a lot. You know, how you're writing some JavaScript and you think man, I wish JS allowed me to make user-defined unary plus operator semantics like C# does. – Eric Lippert Nov 1 '11 at 15:50
  • 2
    @Eric I did not realise it was overloadable. wow you could do some nasty obfuscation with that :) – ShuggyCoUk Nov 1 '11 at 16:08

Defaulting numeric literals to double

For most business apps, decimal is more appropriate anyway... or maybe it would be better to just remove the idea of a default, and force developer to actually make the choice.

(That "remove the default" would be appropriate for some other things, too. For example, I've given up trying to persuade everyone that classes should be sealed by default, but I suspect it's easier to persuade people that they should think about whether their new class should be sealed or not, and make it explicit.)

  • I'd perhaps lean to identifying literals that imply a value that cannot be represented as a double/float precisely... – ShuggyCoUk Nov 1 '11 at 16:10
  • If they're into Java - refer them to the sacred texts by Joshua Bloch "design or document for inheritance or else prohibit it" martinfowler.com/bliki/DesignedInheritance.html IIRC kotlin does seal classes by default, so the industry is moving into a better direction in this respect. – Elazar Leibovich Aug 29 '12 at 18:48
  • Why should classes be sealed? – James Jan 6 '13 at 3:34
  • @James: For exactly the reasons Josh gives. Designing a class which enables inheritance in a sensible, consistent way takes time - and doing so without knowing how inheritance is going to be used is even worse. – Jon Skeet Jan 6 '13 at 8:46
  • 1
    @Pacerier: Think about immutability, for example. A non-sealed class can't claim to be immutable, as subclasses can introduce mutability. – Jon Skeet Aug 30 '14 at 7:17

This is more a guideline than a feature, but I think it's important because it's already too much ingrained in people's minds as the canonical and best solution:

The official pattern to implement IDisposable.

It's cumbersome and there're better ways.


I know there are big differences between the various timer classes. But couldn't we get rid of one or two of them, anyway?


Methods and types of Array and List<T> that became obsolete with Linq, for example:

  • Array.TrueForAll can be replaced with Enumerable.All
  • Array.FindAll can be replaced with Enumerable.Where
  • List<T>.ConvertAll can be replaced with Enumerable.Select
  • Predicate<T> can be replaced with Func<T, bool>
  • Converter<T,R> can be replaced with Func<T, R>
  • IComparer<T> really should be a delegate Func<T, T, int>
  • 3
    I like the Predicate<T> because it captures the intend on how the function is used and saves a tiny bit of typing. – Zebi Jun 19 '11 at 15:41

Non-generic Delegates Like non-generic collections, non-generic delegates are useless now that we have Func and Action series. And I would have cut off the variants at three parameters. If you have more than three parameters, make a structure and use that as the single parameter. Declaring a specific delegate for event handling is not very DRY.

  • 3
    How would you define a delegate to a method that takes a ref int with Action or Func? How would you define a combinator with Func? That is, there's no way to say "delegate D D(D d);" with Func. – Eric Lippert Jan 28 '11 at 20:38
  • 2
    hmmm...I stand corrected. That's why I leave the job of creating the tools I use in your capable hands ;) – Michael Brown Jan 28 '11 at 21:02
  • @EricLippert: I'd like to see a special delegates class which would through CLR magic contain delegates of "every" arity and combination of value/reference parameters [searching for a delegate in the magic class with a suitably-formatted name would create the type], and have all delegates of proper signature inherit from that. Code which wants a particular delegate would still require an exact type, but code which wants a particular signature could use the magic name. – supercat Mar 12 '14 at 6:49

asmx Web Services

I think they are quite obsolete with WCF nowadays.

  • 6
    Yeah, but sometimes much easier to grok . . . – Wyatt Barnett Jun 3 '11 at 21:45

It would be nice not to have to navigate between two desktop platforms. WPF is where things are going, so its frustrating to have a full on platform level redundancy.

  • Winforms seems much more stable, faster, and less buggy than WPF... – Pacerier Aug 29 '14 at 23:04
  • When you just need to hack out a small desktop app, WPF is major overkill. – Kyralessa Mar 4 '15 at 15:32
  • It seems in between WPF has become pretty obsolete in favor of WinRT. However, to me it seems Winforms is more alive than WPF in business development. See also stackoverflow.com/questions/913417/… – Doc Brown Sep 27 '16 at 13:51

Not the answer you're looking for? Browse other questions tagged or ask your own question.