18

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.

Maniero
  • 10,816
Gulshan
  • 9,532

12 Answers12

35

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.

Eric Lippert
  • 46,558
33

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.

Michael Brown
  • 21,822
29

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>.

Eric Lippert
  • 46,558
24

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

Eric Lippert
  • 46,558
22

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.)

Eric Lippert
  • 46,558
14

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.)

Eric Lippert
  • 46,558
12

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.)

Jon Skeet
  • 3,396
7

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.

Jordão
  • 651
6

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

nikie
  • 6,333
4

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>
nikie
  • 6,333
2

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.

Michael Brown
  • 21,822
-1

asmx Web Services

I think they are quite obsolete with WCF nowadays.

fretje
  • 310