Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

With nearly 60 answers to this question it's highly likely that your answer has already been posted. Please don't post an answer unless you have something new to say

Assume that your objectives are the same as for C#. I don't want an answer like "I'd write Python instead". I'm only interested in changes in the language itself - not in the standard library. Perhaps this would be interesting to discuss, but as it is shared between many languages it would be better to discuss this in another question instead.

Please post a single idea per answer; if you want to post several ideas, post several separate answers. Thanks!

share

locked by Yannis Rizos Dec 18 '12 at 16:59

This question exists because it has historical significance, but it is not considered a good, on-topic question for this site, so please do not use it as evidence that you can ask similar questions here. This question and its answers are frozen and cannot be changed. More info: help center.

closed as not constructive by Mark Trapp Aug 4 '11 at 19:24

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.If this question can be reworded to fit the rules in the help center, please edit the question.

1  
I think perhaps I misread this question when I answered it. Not that my answer is wrong, but there's tons of stuff I'd like to change for C#, but that is of course never going to happen. I will, however, very much like to contribute future improvements that won't break existing code. Bitching about missing features, that when added would break existing code might be all well and good, but it's not very constructive, unless you hope they create D# or some other new languages and just go with everything they learned from C#. –  Lasse V. Karlsen Sep 24 '10 at 8:30
show 3 more comments

56 Answers

up vote 58 down vote accepted

Erase from history C# 1.0 along with .NET 1.

I think the legacy of the non-generic past is the single biggest detriment to the consistency of the whole platform.

share
4  
Absolutely. Just look at how many questions on StackOverflow still use ArrayList and untyped IEnumerable’s!... –  Timwi Sep 22 '10 at 10:41
12  
@Matt the question had this dreamy supposition of "if I could"... And if I could I would certainly erase C# 1.0 and start with 2.0 without all the artifacts. –  romkyns Sep 22 '10 at 19:07
1  
@sinni800: You routinely store objects of an anonymous type in an ArrayList?! How do you ever use those objects when you take them back out except via Reflection? Remind me not to try to maintain your code... –  Timwi Feb 22 '11 at 20:54
show 6 more comments

Allow default value setting in auto-properties, and the addition of the readonly keyword. eg

public int MyProperty { get; private readonly set = 100; }
share
2  
That would be awesome ! It always annoy me when I need to create a default constructor just to initialize auto-properties. And the fact that I can't create real readonly auto-properties... –  Thomas Levesque Oct 18 '10 at 8:03
add comment

The syntax of the switch statement. I would like it more "block oriented", and more like the rest of C#.

switch (foo) {
   case 1 {
      // ...
   }
   case 2, 3 {
      // ...
   }
   case 10..100 {
      // ...
   }
}
share
36  
And for the switch statement, for ordinal types, I would add ranges, like case 10..100, or case 'A'..'Z'. –  Lasse V. Karlsen Sep 11 '10 at 20:38
12  
Or even, pattern matching or boolean functions in cases. For example: case oneOf({1,2,3}) –  SHiNKiROU Sep 11 '10 at 22:00
2  
The case statements currently support brackets (which is nice for scoping issues), but you still have to include the colon and VS messes up the formatting. –  Runscope API Tools Sep 11 '10 at 22:56
1  
It's annoying to always have to have the break statements when they don't really do anything (because fall-through isn't allowed). –  Kyralessa Oct 18 '10 at 2:37
2  
@shinkirou but, please, only if it can be analyzed statically, to keep the exact condition known at compile time. –  romkyns Oct 18 '10 at 10:44
show 3 more comments

I would add support for:

  • Extension properties (if only to make fluent interfaces more fluent)
  • Extension operators

    listbox1 += "line"
    
  • Support for operators with generics (ie. specify that you don't really care about the type of the T, but that it has to support "addition" with the + operator)

    public class T Accumulate<T>(IEnumerable<T> values)
        where T : operator +
    {
        using (IEnumerator<T> enumerator = values.GetEnumerator())
        {
            if (!enumerator.MoveNext())
                return default(T);
            T result = enumerator.Current;
            while (enumerator.MoveNext())
                result += enumerator.Current; // this does not compile now
            return result;
        }
    }
    
  • More generic constraints, like "number" or "enum"

    public class Adder<T>
        where T : number
    
share
9  
I think you should split these up into separate answers so that we can vote on them separately. –  Timwi Sep 22 '10 at 10:42
3  
I'm sure Anders Hejlsberg will see this or someone will tell him about these features :) –  Junior Mayhé Oct 25 '10 at 0:15
1  
-1 for adding undue visibility to unpopular ideas, as highlighted by all the +1 comments. They should have been posted separately. –  romkyns Oct 28 '10 at 8:53
1  
where T: operator + is ambiguous. The syntax would have to specify what operator and what operand type(s) you need. For example, where T: operator+(T) would mean the unary plus operator; where T: operator+(T, string) would mean an addition operator that can take a string as the second operand. –  Timwi Feb 22 '11 at 20:59
show 6 more comments

I would eliminate Null by default from language and framework. Null just when boxing on Nullable class.

share
2  
F# is a production .NET language that has non-nullable reference types. It's the default for any type defined in F# - you have to go out of your way to get the F# compiler to let you set an F# type to null. Not that this has anything to do with C#, except to show that it can be done. –  Joel Mueller Oct 1 '10 at 19:04
3  
@JBRWilkinson: Google for 'Maybe monad' or see documentation of option type in F#. –  missingfaktor Oct 20 '10 at 17:12
5  
@JBRWilkinson the 'problem' isn't so much null, but null as a default and NREs. How often do you find yourself checking if something's null purely to avoid NREs? I'd simply settle for the result of any call to a null object returning null - in most cases that's what I want but have to handle it manually with x = y==null? null : y.abc(); –  Ben Hughes Oct 25 '10 at 0:47
6  
@acidzombie24: No, here on StackExchange we just disagree with comments. Down vote is just to denote an useless or wrong information. –  bigown Oct 26 '10 at 21:23
2  
@acidzombie24: The right use for down vote is just when a question or an answer is wrong or useless to site/question. Of course some users use their votes wrongly. You 're free to do what you think that is right, but SE's objective is provide good answers, not good discussions. Comments can provide some disagreement or contrary opinions. –  bigown Oct 26 '10 at 23:06
show 12 more comments

Make types shorter than int first-class members.

It's just crazy to have to cast the result of byte xor byte back to byte.

share
2  
See also my answer here –  Thomas Levesque Oct 18 '10 at 18:06
add comment

Language support for property change notification (INotifyPropertyChanged):

public observable int Foo { get; set; }

The code above would have the same meaning as this:

private int _foo;
public int Foo
{
    get { return _foo; }
    set
    {
        _foo = value;
        OnPropertyChanged("Foo");
    }
}

(this was suggested on uservoice for WPF bindings, but it would be useful in other areas too)

share
5  
Bravo. The overhead of implementing INotifyPropertyChanged irks me :-) –  Jay Beavers Oct 18 '10 at 18:40
2  
Please no, no more keywords!! –  Henrik Feb 12 '11 at 23:07
4  
Downvoting because I don’t see the point in this. I have never used or needed INotifyPropertyChanged, primarily because it is so badly designed that it requires a literal string to be identical to the property name, destroying compile-time checking and all IDE support for renaming it. Your proposed language addition would create a dependency on this badly-designed interface. –  Timwi Feb 22 '11 at 21:07
2  
@Timwi, didn't see your comment until today... The dependency on INotifyPropertyChanged is already there, and it's not going to go away, whether you like it or not. All binding mechanisms (in WPF and WinForms for instance) rely on it. And with this solution, since the boilerplate code would be generated by the compiler, you wouldn't need to worry about mistyping the name of the property. –  Thomas Levesque Apr 11 '11 at 19:33
show 8 more comments

I would add a special Haskell-like syntax for Tuples.

So that instead of this:

public static Tuple<int, int> Divide(int a, int b) {
  return Tuple.Create(a / b, a % b);
}

var t = Divide(16, 3);
var division = t.Item1;
var remainder = t.Item2;

you could write this:

public static (int, int) Divide(int a, int b) {
  return (a / b, a % b);
}

var (division, remainder) = Divide(16, 3);
share
2  
Yep, a tighter integration of tuples in the language would be nice... However I'm not sure how it would fit in the syntax, given the current specifications –  Thomas Levesque Oct 18 '10 at 8:17
show 1 more comment

Not so much a Problem with C# but with the BCL: Wipe out all non-generic collections.

Goodbye ArrayList, Hello List<Object> if you really need a 'non-generic' collection, at least be explicit about it.

Have TableRowCollection actually return TableRow instead of Object.

IEnumerable? Was nice knowing you, now go away.

share
1  
That's one of the biggest constituents of my answer about C#'s non-generic past. I'd love to see this too. –  romkyns Oct 28 '10 at 8:55
show 3 more comments

I would want a placeholder syntax (_) for lambda expressions (like in Scala).

Consider the following code:

var namesOfAdultUsers = users.Where(c => c.Age > 18).Select(c => c.Name);

With placeholder syntax, this could be written more succinctly as follows:

var namesOfAdultUsers = users.Where(_.Age > 18).Select(_.Name);
share
4  
It would be nice, but I think we would need a different placeholder, since _ is a valid variable name (crazy as it seems) –  Thomas Levesque Oct 18 '10 at 8:24
7  
@Thomas: How about using $? users.Where($.Age > 18).Select($.Name); looks okay to me. –  Joe D Oct 25 '10 at 16:03
show 14 more comments

Better support for type safety when dealing with reflection. As it is right now, I have to look things up using strings. Some libraries that use a lot of reflection, like Fluent NHibernate, solve this problem using expression trees, but it really shouldn't be necessary.

Why are my options things like:

foo(typeof(Bar).GetProperty("PropA"))

or

foo<Bar>(x => x.PropA)

Why not just:

foo(typeof(Bar.PropA))

Where typeof returns not a System.Type instance, but also MethodInfo or PropertyInfo depending on how it's used.

share
6  
For those who haven't seen it, In Foof We Trust is Eric Lippert's post on this topic. –  romkyns Sep 22 '10 at 10:27
2  
infoof wouldn't be such a good idea for methods, because of overloading, but properties, fields or events don't have that problem. It could be pretty useful –  Thomas Levesque Oct 18 '10 at 7:55
show 3 more comments

Numeric literal suffixes for all numeric types

Currently the following suffixes exist :

  • 1 (no suffix) : int or double (based on decimal separator)
  • 1U : uint
  • 1L : long
  • 1UL : ulong
  • 1f : float
  • 1d : double
  • 1m : decimal

For other numeric types, you have to cast explicitly :

  • (byte)1
  • (sbyte)1
  • (short)1
  • (ushort)1

I'd like to have the following suffixes added :

  • 1B : byte
  • 1SB : sbyte
  • 1S : short
  • 1US : ushort

And since there is a BigInteger type in 4.0, it would be nice to have a suffix for it too (perhaps use lowercase b for byte, and uppercase B for BigInteger)

share
show 2 more comments

The ability to write a ToString() extension method for enums.

So I can do something like:

public enum AmazingEnum
{
    amazingValue = 0
   ,reallyAmazingValue
   ,unbelievablyAmazingValue
}

public static class AmazingEnumExtension
{
    public static string ToString(this AmazingEnum amazingEnum)
    {
        switch(amazingEnum)
        {
         case AmazingEnum.amazingValue:
              return "This is amazing!";
         case AmazingEnum.reallyAmazingValue:
              return "This is REALLY amazing!";
         case AmazingEnum.unbelievablyAmazingValue:
              return "This is UNBELIEVABLY amazing!";
        }

        throw new ArgumentException("This is an invalid AmazingEnum", "amazingEnum");
    }
}

and call it like this:

string value = AmazingEnum.amazingValue.ToString();

As things work at the moment, the ToString() of System.Enum gets called due to how override resolution works.

share
11  
Or, more generally, the ability to declare methods on enums. The ability to override ToString() would just be a special case of that. –  Timwi Sep 22 '10 at 10:45
3  
The common practice in this situation is to decorate the enums with a DescriptionAttribute and use another class to pull the description. An added benefit is having a generic class for all enums as well as easy internationalization. –  Matt Olenik Sep 22 '10 at 18:22
3  
In general I'd make enums easier to work with in C#. I've never understood why there's not an implicit conversion from an enum of type int to an int. In VB .NET there is, even if Option Strict is on. –  Kyralessa Oct 18 '10 at 2:38
show 10 more comments

I would add

foreach(thing t in things)
{
//do stuff
}
else
{
//this only runs if there are no iterations above
}

probably could work with other loop types too

share
show 2 more comments

Virtual methods could have been a lot more flexible. A derived type should be able to make a virtual method more general. In particular:

  • A virtual-method override should be able to specify a more general parameter type (a base class or an interface).

  • A virtual-method override should be able to specify a more specific return type (a subclass).

  • A virtual-method override should be able to loosen the constraints on its generic type parameters.

  • A virtual-method override should be able to broaden the accessibility modifier.

The only problem with this is a subtle form of brittle base class which would hardly occur in practice. Beside that, none of these would cause any trouble with compile-time type safety, nor any accessibility loopholes.

share
1  
@Sjoerd: That is a completely different kind of variance than the variance Timwi is talking about. C# 4 has variance on reference conversions of generic interfaces and delegates. Timwi wants variance on virtual method overloads. –  Eric Lippert Oct 14 '11 at 16:17
show 7 more comments

In C#/.NET, there is no consistent support for deep equality. Most Equals() and operator==() implementations in .NET merely do Object.ReferenceEquals(), but there are exceptions, such as String. As a result, you need to implement your own equality function for just about every class in the .NET library. Furthermore you need to memorize for each class which comparison function you need to use: operator==(), Equals() or MyOwnEqalityFunctionAsExtensionMethod().

share
add comment

Enforcing that Linux and OS X are officially supported platforms.

Currently it is vendor-lock in.

share
add comment

Embed Reactive Extensions

While I'm still coming up to speed on this technology, it seems to me that it has some great implications for improving UI -> business object decoupling (thereby reducing memory 'leaks' from forever-referenced objects) and for helping with M-V-VM design.

See Reactive Extensions for details.

share
add comment

Introduce an abstract/interface .ctor, which would require derived types to implement a .ctor with matching arguments. This would solve the limitations of the new() constraint in generics. I'd also make the constructor named this, or self for consistency.

In addition, constructors could be made virtual to mean they are replicated in subclasses (unless overridden). So that you don't need to bother manually adding those constructors who just pass their arguments to the base class anyway. (and do nothing else).

Delayed construction would be useful here, in the event you wish to perform some calculations on the parameters before calling the base constructor - although this can be a dangerous weapon if used incorrectly.

share
3  
I'd be happy to see the new() constraint expanded so that you can say where T : new(int, int) to mean "T must have a constructor that takes two integers". –  Dean Harding Oct 18 '10 at 4:32
add comment

It'd be nice if unassigned event handlers wouldn't throw a NullReferenceException and had a built-in thread-safe implementation for calling. You should be able to do this:

PropertyChanged(this, new PropertyChangedEventArgs("Foo"));

instead of having to do this:

PropertyChangedEventHandler h = PropertyChanged;
if (h != null)
{
   h(this, new PropertyChangedEventArgs("Foo"));
}

I really can't think of any risk a change like this would introduce, other than code not being backward-compatible once it was added to the language.

share
show 2 more comments

I would have designed out and ref parameters properly, not the hack that C# has now. In particular:

  • out should have been implemented just like the return value: the value should be copied into the out location when the method returns.

  • Inside the method body, assignments to an out parameter within the method should not modify a storage location outside the method (which was passed in by reference).

  • ref should have been implemented in such a way that it would be functionally equivalent to having two parameters: one in and one out.

  • This would enable out parameters to be contravariant just like the return type, and just like in parameters are covariant. Only ref would need to be invariant.

share
2  
I'm not a C# expert, but it sounds like ref is implementing classic call-by-reference. You are asking for ref to have call-by-value-result semantics. –  Stephen C Oct 1 '10 at 7:44
show 3 more comments

Get rid of public static class.

There's no reason to pack everything inside classes when the functions can do just as well as free functions in namespaces.

share
2  
@qstarin: By adding the feature to the language? That seemed rather an obvious one to me. –  greyfade Nov 25 '10 at 16:31
show 2 more comments

Add some helpful syntatic sugar for the decorator pattern (i.e. composition not inheritance)

interface IWindow {
    public void Draw();
    public void Close();
    ... more methods ...
} 
sealed class SimpleWindow: IWindow {
    public void Draw() {/* draw window */}
    ... more methods ...
}
//extending this to add a scoll bar
sealed class ScrollBarDecorator : IWindow {
    private IWindow _component; //component class that has the basic implementation

    public VerticalScrollBarDecorator (IWindow decoratedWindow) {
        _component = decoratedWindow;
    }

    //"override" the behaviour we want to change/extend (one line)
    public void IWindow.Draw() {
        DrawScrollBar();
        _component.Draw();        
    }

    //then type lots (potentially pages) of boilerplate code to forward the rest of the methods straight to the underlying component
    public void IWindow.Close() {
        _component.Close();        
    }
    ... more methods ...
}

Unpleasant. Most people won't bother or will find any way to avoid this (i.e. damaging their class structures, twisting their code, bloating type hierarchies) - whereas, if we had a bit of syntatic sugar for this:

sealed class ScrollBarDecorator : IWindow {
    //note the new keyword "decorates"
    decorates private IWindow _component;

    public VerticalScrollBarDecorator (IWindow decoratedWindow) {
        _component = decoratedWindow;
    }

    //"override" just the behaviour we want to change/extend
    public void IWindow.Draw() {
        DrawScrollBar();
        _component.Draw();      
    }
 }

Finished. The boiler plate code to implement IWindow, delegating all the calls to _component would be implied/generated by the compiler. Far more coders would use this pattern if it were this simple to type.

share
show 1 more comment

I would implement anonymous iterators.

share
1  
@Thomas: Sorry, I was a bit unclear. I asked Eric Lippert multiple times what part of the implementation is missing and have not heard from him. I think we can all agree that anonymous methods are already implemented, and iterator blocks are already implemented. Eric’s description of the two algorithms responsible for these, indicates that the algorithms are orthogonal and can trivially work in serial to allow anonymous iterators. So far nobody has been able to explain to me what would go wrong if the compiler error were simply removed and the algorithms allowed to run together. –  Timwi Oct 19 '10 at 14:37
1  
The algorithms as implemented today are not orthogonal and cannot trivially be made to work serially. If they could have, I would have done so long ago. If you want "evidence" because don't trust my opinion as the guy who has had to work with that codebase for the last six years, then I don't know how to satisfy you. The significant engineering budget that would be required to make iterator state machine rewriting work well with closure rewriting has instead been spent on making closure rewriting work with async await rewriting. –  Eric Lippert Oct 14 '11 at 16:33
1  
As a result, we now know that we can have nested async lambdas, performing both state machine rewrites and closure rewrites at the same time. This is points in favour of someday being able to extend that work to iterator block lambdas. But having the infrastructure in place and knowing that we can do the engineering work is only one small part of the feature. We also have to do considerable design, testing, and user education work, all of which have limited budgets. We have to decide what the best way to spend that budget is, and so far iterator block lambdas aren't the best way. –  Eric Lippert Oct 14 '11 at 16:36
show 7 more comments

System.ValueType, System.Enum and System.Delegate would be a lot more useful if they worked everywhere where you can reasonably expect them to work. Currently they do not work:

share
show 1 more comment

It'll be nice if type inference is extended to collection initializers. So that instead of writing the code like following:

var dict = new Dictionary<int, List<string>> {
  {1, new List<string> {"ek", "one", "ooga"}},
  {2, new List<string> {"don", "two", "bira"}}
};

I could just write:

var dict = new Dictionary {
  {1, new List {"ek", "one", "ooga"}},
  {2, new List {"don", "two", "bira"}}
}
share
1  
@Junior: You can specify the type when you need it. See this Scala example to understand what I mean: ideone.com/cWBx8 –  missingfaktor Oct 25 '10 at 4:22
show 2 more comments

There is no consistent support for deep copying. Most classes in the .NET library don't have a Clone() function. As a result, it is for example impossible to provide a deep clone function for a generic List.

share
add comment

Get rid of the C# 2.0 syntax for anonymous methods.

It's worse than the lambda syntax, and the only reason we need both is for backwards compatibility with C# 2.0 code.

share
2  
The old syntax can actually be useful sometimes. For instance, if you don't need to use the parameters, you can just "forget" them in your delegate declaration, like so: Action<Foo, Bar> myAction = delegate { Console.WriteLine("Hello world"); } –  Thomas Levesque Oct 18 '10 at 8:16
show 2 more comments

I've always wanted static interfaces for some reason. Maybe it's just me.

share
show 3 more comments

Enable the creation of classes that have access to each other's private members, without letting the whole assembly see them.

Use case: basically pretty much every time you use "internal" on a field or a method. This usually means you require a backdoor which the client code should not have. But if the client code should not have that backdoor, why should the rest of your assembly? Limit it to just the one or two classes that actually need that backdoor.

share
2  
@Jaco - he wants to limit the types that can access it, rather than all in the assembly. Basically the equivalent of friend from C++. (You can do this using separate assemblies and InternalsVisibleTo, but that's rather awkward. –  Mark H Sep 22 '10 at 6:56
1  
Oh, interesting. Can't really say that I've ever felt the need for this. –  Jaco Pretorius Sep 22 '10 at 7:46
1  
@David So let me get this straight, you think that the only justified access modifiers in properly written code are private, protected and public? –  romkyns Sep 28 '10 at 0:51
3  
@David Lively I strongly disagree. In C++ friend allows you to make thing private which would have to be public otherwise. So it improves encapsulation instead of breaking it. In Java or C#, the package-wide or assembly-wide visibility makes most uses of friend unnecessary, but not all of them. –  maaartinus Apr 16 '11 at 21:37
show 4 more comments

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