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

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

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

Provide a macro system similar to Python's decorators, or maybe just make attributes more powerful. Using dynamic proxies or IL rewriting for simple AOP features like tracing or transactions is just overkill.

share
show 3 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

I'd like to see the ability to pass properties by reference. Like

int.TryParse(some_numeric_string, out MyProperty)

It's already been done in VB, so it's definitely possible.

share
3  
This would go well with a better design for out and ref which I suggested earlier, but of course due to backwards compatibility we can’t have that :( –  Timwi Sep 23 '10 at 11:33
show 6 more comments

Mine's a fairly simple one - i'd have preferred it if properties and methods were virtual by default.

share
5  
Like in Java IIRC... Not sure it would be a good idea. Designing a class for inheritance is not as easy as it seems, because there are lots of cases you need to consider to make it solid. See Eric Lippert's articles about the brittle base class problem. –  Thomas Levesque Oct 18 '10 at 8:12
show 1 more 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

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

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

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

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

share
show 3 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

Remove static entirely, and replace with pure for methods and threadlocal for fields. Any data to be shared between threads should be passed as immutable data.

share
show 3 more comments
  1. Improved support for defining local helper functions. Anonymous methods bring disproportionate runtime + code-size overhead, can't be generic, and recursive anonymous methods are very clumsy.

  2. Support for a generic type parameter constraint specifying constructor signature(s).

  3. Support for a generic type parameter constraint specifying method/property signature(s).

  4. Nullability should be handled consistently across reference and value types and disabled by default. "nullable string" and "string" should not be represented by the same type.

  5. A module system like SML's. The closest things C# has to approximating this are generics + interfaces and neither can unify multiple implementations of a set of related types and functions.

  6. Allow a default value to be specified for automatically generated property getters/setters

  7. Convenience features stolen from functional languages: pattern matching expression, let..in expression, etc.

  8. Extension properties, extension constructors.

share
4  
Next time, please post separate answers, not a list of several in one. Thanks! –  Timwi Sep 22 '10 at 10:44
3  
Just so you know, I would have upvoted a couple, but I don't want to upvote the rest... so no upvote at all. –  romkyns Sep 22 '10 at 10:51
show 1 more comment

I want to be able to have lambda expressions in custom attributes. For example...

[SomeAttribute(p => some_code(p))]
public string SomeField;

For reasonable flexibility, custom attributes should be able to be generic, so that the lambda expression can be properly typed:

[SomeAttribute<string>(str => some_code(str))]
public string SomeField;

This should be pretty simple to implement in the CLR and the C# compiler, too. Just turn the lambda expression into a static method on a special compiler-generated static type that contains all these methods for all those lambda expressions in custom attributes. Then compile the custom attribute data to one that contains the metadata token for that method. The CLR would recognise that the parameter is of a delegate type and automatically turn the metadata token into a delegate by calling Delegate.CreateDelegate() when the custom attribute is requested.

share
show 4 more comments

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

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

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

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

i'd have preferred if LINQ to SQL is compatible with the others database types (Oracle,MySQL,PostgreSQL...)

share
7  
That's more of a libarary/tooling issue than a language feature. –  Mark H Sep 22 '10 at 12:07
1  
No, use NHibernate. ;) –  Henrik Feb 12 '11 at 23:15
show 1 more comment

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

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

I would restrict var to enumerable query results (probably would change the keyword to query at the same time), create a contextual keyword called anon to deal with anonymous types outside of query results, and then make the class name optional on the right side in an initialization statement.

It would cut out utter crap like

var mystring = "lol"; // not permissable, lazy bum
var randomObject = ThisFunctionNameMeansNothing(); // get the freak out

While still cutting down on space produced by generics and long class names

MyRidiculouslyLongClassName<string, int, Foo> myClass = new();
share
show 2 more comments

Get rid of the var keyword.

Allow fall-through cases in switch() without having to jump through hoops.

I'd love a version that's less entangled with the framework that could be used to generate native code. C# is a lot like Delphi (thanks, Anders!) which used the Borland C++ compiler back-end. There's no reason C# couldn't do the same with MSVC.

Support for inline assembly. Just because I'm crazy like that.

A neat trick would be to build something that compiles C# into C++. You'd get to keep succinct syntax, a great object model, good exception handling, etc. I know there's no 1:1 correspondence between the two languages on many points, but it's possible. Yeah, I'll get right on that (not).

share
5  
What is wrong with the var keyword? Much nicer than having to deal with a swarm of types –  Casebash Sep 27 '10 at 23:10
1  
It introduces inconsistencies in code. If you change the way a variable is used, it can change the type that it is resolved to. It's just lazy. –  David Lively Sep 28 '10 at 16:03
5  
You see it as lazy, I think telling the compiler something it already knows is a waste of keystrokes and meaningless ceremony. C# needs more type inference, not less. Switching from F# to C# feels like a giant step backwards, most days. –  Joel Mueller Oct 1 '10 at 19:11
4  
Linq wouldn't exist without the var keyword. They're required for anonymous types. –  Thomas Levesque Oct 18 '10 at 8:20
show 5 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

Smarter if statements ie:

object foo = GetAnObject();
if(foo is string) 
    Console.WriteLine(foo.ToUpper());//foo is typed as string
else if(foo is int)
    Console.WriteLine(foo + 2);//foo is int
share
1  
programmers.stackexchange.com/questions/2815/… is basically the same idea, but implemented better. –  Timwi Oct 28 '10 at 14:46
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

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