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

56 Answers 56

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

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

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

I would add Duck-Typing. Think of it as implicit interfaces. If an object implements the set of methods that compose an interface it is considered to implement that interface, even if the class does not explicitly name it.

share
2  
+1, but the right technical name for this is 'structural typing', not 'duck typing'. –  missingfaktor Oct 25 '10 at 4:09

First about this, is that I don't like the way this question is posed specifically the requirement of one answer for post, since that is a call for spamming.

So, I would leave all my answers in one post, and let people vote accordingly, and if they want specify the one they like or don't in the comments to this answer.

  1. I would go and remove everything that only has one use, since there is probably some other way of doing that without that change;

  2. Make the language more stable, so that it don't change as the versions of visual studio or .net change, that would do a lot for the language adoption, since it is what java always had, and java is the language of the seven lifes.

  3. Remove lambda expressions, since delegates are more general and do the same.

  4. Remove the var keyword, or add the requirement that you either use vars (dynamic types) or static types, since it is a mess to find both of them in the same function!

And thats all, folks...

share
2  
It seems that you have an incorrect understanding of what “spam” means. None of the answers are unsolicited; nor are they adverts; nor are they addressed directly at large numbers of recipients. I’m going to downvote this because I disagree with one of your bullet points and I can’t vote on them separately. –  Timwi Feb 22 '11 at 20:41
2  
① is too vague; what are you even talking about? ② C# is more stable than Java; there have been long and painful discussions about how to avoid even the most minor breaking changes in C#; ③ that would be a breaking change, duuuhh (and also a dumb one; lambda expressions are no less general. If anything, remove the old delegate syntax); ④ Clearly you have no idea what var does; it has nothing to do with dynamic typing. — Well, looks like I ended up disagreeing with all of them, not just one... –  Timwi Feb 22 '11 at 20:45

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

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

Eliminate "ref" and "out" parameters

Surely there has to be a better way, I cringe every time I has to use a BCL method with ref parameters (like TryGet)

share

"raise" keyword for events

I'm tired of writing small methods just to trigger events thread-safely.

share

I would like to be able to add white space to values inside of enums. I know this seems minor but it actually comes up a lot.

share
1  
Sounds like you are using ToString() on your enums to generate user-visible text. Bad practice. How are you going to internationalise that? –  Timwi Feb 22 '11 at 20:38

I'd change the name - C# - Google ignores that # character when you search for language-related things so you get unsolicited results for C/C++ stuff.

share

I would make the language and also the common language runtime have yet more static typing with; kinds, monads and type-classes. It would allow all the generic constraints suggested above, on both methods and properties.

This discussion on channel9 shines some light on why this would be great in a multi-core world. Principally it would allow you to encapsulate state changes into the type system, allowing for greater library optimisation and improvements.

share

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

Sometimes I miss friend class and functions. They are quite powerful in some scenarios.
Apart from that they can also help in unit testing private methods of a class.

share
1  
Yes, definitely. My answer provides a Microsoft Connect link where I make a suggestion that might possibly fit within the .NET ideology (I doubt true "friend" would). –  romkyns Nov 24 '10 at 23:34

One thing that I miss from my C++ background is const correctness. i.e. do not allow constant objects to be changed.

share

I want indexers not to limit modification. like this:

...
// MyList<T>
public this[int index]
{
get{/*do something to return value*/}
set{/*do something to set value*/}
}
...

so:

MyList<MyPersonClass> lst = new MyList<MyPersonClass>();
lst.Add(SomePeople);
lst.Add(SomeOtherPeople);
lst[0].name = "Fred";    // error
lst[1].last = "McKenny"; // error
share
4  
Indexers don't limit modification. The error you mention only occurs if you make a list of structs, and that's for a good reason. Your last two lines aren't calling "set", they are actually calling "get", and you are modifying the value returned. But structs are copied around, so not having an error there would just modify a temporary and discard it. Note that it works fine for actual classes. –  romkyns Apr 17 '11 at 1:18

Some syntactic sugar for the long-winded type-check-and-cast:

if (obj is MyType)
{
    var o = (MyType) obj;
    <use o>

e.g.

if ((var o = obj as MyType) != null)
{
    <use o>

or something a bit less ugly and more thought-through.

Better still, perhaps some special support for polymorphic extension methods. Code like the above is often the result of writing an extension method that would really have been a virtual method with overrides had it been implemented in the original class.

share

Case-sensitivity.

I'd make C# autocorrect case like VB .NET does, so that whether you type in all caps or all lower-case or a mixture, your code comes out in the correct case once you move off the line.

It vexes me greatly when I type the name of a class, but I don't happen to capitalize it, and C# pretends it has no idea what I'm talking about.

share
1  
VB's case insensitivity feels decidedly clunky to me. (And I started with a VB language.) –  Nick Oct 25 '10 at 8:05
2  
Upvoting! There is really no need at all for case-sensitivity. Humans just don’t think like that. –  Timwi Oct 28 '10 at 14:45
2  
I wonder if I would've gotten better votes on this if I hadn't mentioned "VB .NET". –  Kyralessa Nov 5 '10 at 3:54
1  
In principle, case sensitivity is an enormous pain in the ass. In practice, intellisense makes it trivially easy to use properly, so now you have all of the benefits of case sensitivity without the hassle. Having worked with VB before, and now with C#, I would never go back to the ambiguity of case insensitivity. –  Robert Harvey Nov 24 '10 at 17:57

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

I'd get rid of the syntax litter like {} and ;. And var (which makes a C# programmer a VB.NET programmer)

share

Not sure if someone put something about automatic casting:

int age = 70;
var foo = "John Lennon would be " + age + " years old";
Console.WriteLine(foo);

//---- output
John Lennon would be 70 years old
share
3  
You know, if you just create a new console project and paste this exact code into the Main method, it will produce that exact output :))) –  romkyns Oct 28 '10 at 9:07
2  
As romkyns already mentioned, C# already does exactly this. Furthermore, however, I’m downvoting this because if it didn’t, then I would prefer if it were not added because it destroys some of the static typing and makes it very easy to make the kinds of mistakes that normally only occur in dynamic languages (e.g. “The names are: String[]” because you forgot a string.Join...) –  Timwi Oct 28 '10 at 14:31

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

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

Enforcing that Linux and OS X are officially supported platforms.

Currently it is vendor-lock in.

share

Having previously worked in C++ before C#, I really miss templates. Generics are close, but you can't specify non-types as a generic parameter. C++ template parameters allow typenames and primitives (int, enum, etc.). C++ templates also allow defining specializations. This allows for a wide variety of compile-time specialization. This is entirely useful when portability of generics is not a requirement.

share

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

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

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

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

Enums that actually represent a contiguous set of numbers should be permitted for array indexes. Sure, you can easily cast them but that doesn't let the compiler protect you from mistakes. This would also apply to bools.

share
1  
I wasn't the downvoter, but I'm curious to know what scenarios that would solve? –  Dean Harding Oct 18 '10 at 11:22

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