Max Toro
Max Toro

Reputation: 28608

C# to C#, convenience language features

I'd like to learn what are all the convenience features of C#, and how they map to C#.

For example, automatic properties:

public string Foo { get; set; }

...maps to something like this:

string <Foo>k__BackingField;

[CompilerGenerated]
public string Foo {
   get { return this.<Foo>k__BackingField; } 
   set { this.<Foo>k__BackingField = value; } 
}

Foreach loops:

foreach(char c in "Hello") {
   Console.WriteLine(c);
}

...maps to something like this (I think):

CharEnumerator en;

try {

   en = "Hello".GetEnumerator();

   while (en.MoveNext()) {
      char c = en.Current;

      Console.WriteLine(c);
   }

} finally {

   IDisposable disp = en as IDisposable;

   if (disp != null)
      disp.Dispose();
}

The disposing of the enumerator makes foreach very useful when dealing with unmanaged resources, like looping through lines in a file, or records in a database.

I think a good understanding of these high level features can help us write better code. What are other convenience features of C#, and how do they map to C#?

Upvotes: 11

Views: 1747

Answers (14)

Arve
Arve

Reputation: 7506

using is syntax sugar

using(x) 
{
    ...
}

Maps to

try {
    // Code
}
finally
{
    if(x != null)
        ((IDisposable)x).Dispose();
}

The from- thing in LINQ is syntactic sugar

from x in l where y select z;

translates to

l.Where(x => y).Select(x => z);

Upvotes: 8

Zach Johnson
Zach Johnson

Reputation: 24232

The ?: operator, which tests a boolean or boolean expression and returns the first value if the test returns true and the second value if the test returns false:

condition ? first_expression : second_expression

Which essentially means:

var x;
if (condition)
{
    x = first_expression;
}
else
{
    x = second_expression
}

Using the ?: operator, you can write int x = condition ? 10 : 20; instead of having to write out the whole if statement.

Upvotes: 4

Rodrick Chapman
Rodrick Chapman

Reputation: 5543

Collection initializers (and type inference):

var scoobies = new List<Scooby>()
        {
            new Scooby("Buffy"),
            new Scooby("Willow"),
            new Scooby("Xander")

        };

Maps to:

List<Scooby>() scoobies = new List<Scooby>();
scoobies.Add(new Scooby("Buffy"));
scoobies.Add(new Scooby("Willow"));
scoobies.Add(new Scooby("Xander"));

Upvotes: 0

RichB
RichB

Reputation: 520

Unusual amongst high level languages, C# has a 'goto' statement and consequently several other C# statements can be considered to be language translations into the goto statement.

For example, the if() statement maps directly to a goto while the standard for() loop actually maps to a while() loop which maps to a goto.

The switch() statement is unusual as it is compiled differently depending on number of cases and type of the switch argument. Thus it is not possible to consider it a language transformation to goto.

Upvotes: 0

jason
jason

Reputation: 241651

Nullable<T> is another incredible convenience. Especially handy is the ? syntax as in int? is short for Nullable<int>.

Upvotes: 1

Zach Johnson
Zach Johnson

Reputation: 24232

Extension methods.

If this is your extension method:

static class ObjectExtensions
{
    public void ExtensionMethod(this object obj)
    {
        // Do something here...
    }
}

And you call obj.ExtensionMethod()

It translates to:

ObjectExtensions.ExtensionMethod(obj)

If you happen to have a version of the C# compiler that supports extension methods, you can trick the compiler into letting you use extension methods in versions of .Net prior to 3.5 by creating a System.Runtime.CompilerServices.ExtensionAttribute, like this: (It is perfectly safe to do this, since the compiler maps the extension methods into standard IL)

namespace System.Runtime.CompilerServices
{
    using System;

    internal sealed class ExtensionAttribute : Attribute
    {
    }
}

Upvotes: 1

jason
jason

Reputation: 241651

Anonymous types:

var message = new { Message = "Hello, world!", MessageID = 1 };

is translated to

<>f__AnonymousType0<string, int> message =
    new <>f__AnonymousType0<string, int>("Hello, world!", 1);

where

[CompilerGenerated]
[DebuggerDisplay(
    @"\{ Message = {Message},
    MessageID = {MessageID} }",
    Type="<Anonymous Type>"
 )
]
internal sealed class <>f__AnonymousType0<
    <Message>j__TPar,
    <MessageID>j__TPar
> {
    // Fields
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private readonly <Message>j__TPar <Message>i__Field;
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private readonly <MessageID>j__TPar <MessageID>i__Field;

    // Methods
    [DebuggerHidden]
    public <>f__AnonymousType0(
        <Message>j__TPar Message,
        <MessageID>j__TPar MessageID
    ) {
        this.<Message>i__Field = Message;
        this.<MessageID>i__Field = MessageID;
    }

    [DebuggerHidden]
    public override bool Equals(object value) {
        var type = value as <>f__AnonymousType0<
            <Message>j__TPar,
            <MessageID>j__TPar
        >;
        return (((type != null) && 
            EqualityComparer<<Message>j__TPar>.Default.Equals(
                this.<Message>i__Field, 
                type.<Message>i__Field)
            ) &&
            EqualityComparer<<MessageID>j__TPar>.Default.Equals(
                this.<MessageID>i__Field,
                type.<MessageID>i__Field)
            );
    }

    [DebuggerHidden]
    public override int GetHashCode() { 
        int num = 0x2e22c70c;
        num = (-1521134295 * num) +
            EqualityComparer<<Message>j__TPar>.Default.GetHashCode(
                this.<Message>i__Field
            );
        return ((-1521134295 * num) +
            EqualityComparer<<MessageID>j__TPar>.Default.GetHashCode(
                this.<MessageID>i__Field)
            );
    }

    [DebuggerHidden]
    public override string ToString() {
        StringBuilder builder = new StringBuilder();
        builder.Append("{ Message = ");
        builder.Append(this.<Message>i__Field);
        builder.Append(", MessageID = ");
        builder.Append(this.<MessageID>i__Field);
        builder.Append(" }");
        return builder.ToString();
    }

    // Properties
    public <Message>j__TPar Message {
        get {
            return this.<Message>i__Field;
        }
    }

    public <MessageID>j__TPar MessageID {
        get {
            return this.<MessageID>i__Field;
        }
    }
}

Upvotes: 3

Callum Rogers
Callum Rogers

Reputation: 15829

Anonymous delegates get changed into methods during compilation, so this:

var collection = new[] { 1, 2, 3, 4 }.Where(i => i == 2);

causes a new method to be created:

[CompilerGenerated]
private static bool <Main>b__0(int i)
{
    return (i == 2);
}

and changes to:

IEnumerable<int> collection = new int[] { 1, 2, 3, 4 }.Where<int>(<Main>b__0);

Notice that it uses a method name that you cannot create before compiling <Main>b__0 - you cannot have <> in a method name, so it always avoid collisions.

The same process happens to this as well as i => i == 2:

delegate(int i) { return i == 2; }

You will also notice that you can use short hand for:

new[] { 1, 2, 3, 4 }
// goes to...
new int[] { 1, 2, 3, 4 }

and

var foo = new Foo();
// goes to...
Foo foo = new Foo();

Upvotes: 3

Mark Simpson
Mark Simpson

Reputation: 23365

The null coalescing operator (??) can be pretty nifty. This ...

ISomeRef myRef = firstChoice ?? secondChoice ?? fallback;

Translates to something functionality equivalent to:

ISomeRef myRef = firstChoice;
if(myRef == null) myRef = secondChoice;
if(myRef == null) myRef = fallback;

I say functionally equivalent because I haven't looked in reflector yet :)

Upvotes: 3

IgorK
IgorK

Reputation: 906

  1. for, while, do...while, switch -- a controversial answer :)

    You could replace it with some code based on if and goto.

  2. lock(){} could be translated to Monitor.Enter() and Monitor.Exit() within a try-finally with null check (see Does a locked object stay locked if an exception occurs inside it? )

Upvotes: 5

Noldorin
Noldorin

Reputation: 147340

LINQ as a whole (especially using the LINQ query syntax) is essentially a major C#/.NET convenience feature that replaces for-loops/iterators/complex query logic much of the time.

Upvotes: 6

Marc Gravell
Marc Gravell

Reputation: 1062975

If you want to talk about the amount of code saved, the biggest savers (IMO) are:

iterator blocks

Example:

public static IEnumerable<int> Get() {yield return 1; yield return 2;}

Saved:

  • writing an IEnumerable<T> implementation
  • writing an IEnumerator<T> implementation
  • handling state of the enumerator; have you seen how horrible it is? Seriously.

captured variables (anon methods / lambdas)

Example:

var list2 = list1.FindAll(x => (x.Value % 10) == find);

Saved:

  • writing a class to hold the state
    • in complex cases, nested state
  • initializing the state wrapper
  • writing a method on that class

Expression lambda compiler

Example (from above):

Expression<Func<Foo,bool>> pred = x => (x.Value % 10) == find;

Saved:

  • yeuch - lots of tree code; very, very complex; in the above I can see (in no particular order) Expression.Parameter, Expression.Property, Expression.Field, Expression.Constant, Expression.Equal, Expression.Modulo, Expression.Lambda... combine ;-p

Upvotes: 11

Kris Krause
Kris Krause

Reputation: 7326

Object initializers are pretty syntax sugar:

 public class Book
{
 public string Author { get; set; }
 public string Title { get; set; }
}

Book book = new Book() {Author = "John Smith", Title = "C# Syntax"};

The above is another way to write:

Book book = new Book();
book.Author = "John Smith";
book.Title = "C# Syntax";

Implicit types:

var book = new Book() {Author = "John Smith", Title = "C# Syntax"};

Upvotes: 3

herzmeister
herzmeister

Reputation: 11297

Lambda expressions are another example.

var myZombies = myMonsters.Where(monster => monster.Kind == MonsterKind.Zombie);

pulls out the Lambda delegate into its own method with a weird name.

You can use the Reflector and switch between the C# versions in the options dialogue to see the differences of how such things would be resolved.

Upvotes: 1

Related Questions