Reputation: 28608
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
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
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
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
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
Reputation: 241651
Nullable<T>
is another incredible convenience. Especially handy is the ?
syntax as in int?
is short for Nullable<int>
.
Upvotes: 1
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
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
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
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
Reputation: 906
for
, while
, do
...while
, switch
-- a controversial answer :)
You could replace it with some code based on if
and goto
.
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
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
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:
IEnumerable<T>
implementationIEnumerator<T>
implementationcaptured variables (anon methods / lambdas)
Example:
var list2 = list1.FindAll(x => (x.Value % 10) == find);
Saved:
Expression lambda compiler
Example (from above):
Expression<Func<Foo,bool>> pred = x => (x.Value % 10) == find;
Saved:
Expression.Parameter
, Expression.Property
, Expression.Field
, Expression.Constant
, Expression.Equal
, Expression.Modulo
, Expression.Lambda
... combine ;-pUpvotes: 11
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
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