Sean Corfield mentioned I should include a brief overview of the C# features mentioned below, and seeing as he pointed me to this hilarious link, I owe him at very least this : ).

enums 

These are kind of like type safe constants, they can be based on bits or integral types (like byte, int, ulong...). There are many reasons enums are a good thing, a subtle one is when you are debugging and 'x' is an enum type, you will get 'Color.Orange' rather than '6'. When using bits you can have overlap, so for example Color.Primary could test true for Color.Red, Color.Green, and/or Color.Blue. The syntax is pretty straigtforward - it defaults to int and auto assigns if you don't tell it otherwise.

structs

These are like classes, but they are value types. A good example of where they are useful would be a Color class, that has rgba. Even if there were many supporting methods etc, each instance would be stored as four bytes -- so very efficient. These are full value types, so for example copies (not refs) are passed to methods. You can control the byte layout if you wish to, however things like unions aren't allowed.

properties 

These are wrappers for get and set methods. You do not have to declare both, so declaring only a get method is a way of making something (externally) read only. There are a lot of arguments for using get and set, and if you accept them then this formalizes the process, and cleans up your interface a bit.

indexers

Essentially these allow instances that have a natural 'store' to be accessed with array syntax. This allows you to do things like access points in a polygon class's instance like: polygon[2]. You can access hash values too, like myClass["key"]. Strings are at heart a character array, so "hello"[3] would be 'l' (yeaaay - no more substring crap!).

delegates

This can be a bit confusing, especially the related 'events', however this is mostly because it is simpler than it seems. Delegates store method references, events are accessors that add and remove delegates from a list. They both can invoke what they store. Here is the logic, or the jist if you don't feel the following qualifies as logic:
 
Callbacks mostly boil down to references to methods. Methods are identified by their name and parameter types -- however for callbacks we want to be able to add any name. So a delegate only enforces the parameter signature. The delegate then can store a reference (or references - they are multicast) to any methods that have a matching signature. They can of course also invoke these. The documentation on delegates is quite weak, but the idea is simple:

// This is a type (not an instance) that can store references to any methods --
// as long as the methods have one argument and it is a string. The name
// of the type we create here is MethodRefs.
delegate void MethodRefs(string s);
...
// later, create an instance of that type, so now there is
// an instance you can dump method references into
MethodRefs holder = new MethodRefs();

// Adding a reference to a method is conceptually like below,
// however in truth you have to add the refs via the constructor
// (or by combining two or more delegates together).
// This assumes that there is a PrintString method somewhere
// that takes one string argument.
holder.Add(PrintString);

// To invoke the methods stored in the delegate, you just 'invoke'
// the delegate as if it were a method.
holder("hello"); // calls PrintString("hello") in this case

events

Delegates can store methods with specific signatures, and if you like you can get by with just these. Normally you want to create a public instance of a delegate, and then add and remove method references to it. This is what events do. The trick to understanding events is that they are accessors (like properties, which are also accessors). Where a property wraps get and set methods that usually access private fields, events wrap add and remove methods that access a 'private' delegate collection. Note they don't store method references like delegates do, they store delegates themselves. Getting at the 'add' and 'remove' methods is done with += and -=. You can declare your own add and remove accessors for an event, but usually you just use the defaults. Like default constructors, you don't have to declare these.

// declare an event accessor, of type MethodRefs (the type from
// the above delegate example), and name it Print. Note the add
// and remove methods are not declared - if they were it would look
// much like a property, with add and remove instead of get and set.
// We give this event the name 'Print', so it is the 'Print event'
public event MethodRefs Print;

// create a delegate instance (the proper way this time)
// again we assume there is a method out there called
// PrintString that takes one (string) arg
MethodRefs holder = new MethodRefs(PrintString);

// add the delegate (events store delegates, not method references)
Print += holder;

// Raise the Event
Print("Easy as pie.");

As long as you avoid the sample code in the docs(!), delegates and events are quite easy to understand and use.


attributes 

Attributes are a way to add your own custom metadata to a code element. An 'a-ha' moment I had when first reading about attributes was to understand that 'public' and 'private' are actually also attributes. They don't have anything to do with the content or structure of the code, only about how and where the code is allowed to be used. So the idea is you can define your own metadata - for example you could mark methods with [Test] and use reflection to find and run those while unit testing. There are some attributes common in the framework, for example [ClsCompliant] enforces compliance with the common language specification, ensuring your code can run from other .Net languages. [Flags] on an enum will cause them to be stored as bit flags. It is very easy to create and use your own custom attributes.

operator overloads 

Probably some people disagree this is a feature, but it can make libraries much easier to work with. Essentially if you create your own class called ReallyBigNumber, you can set it up to work like the rest of the built in numeric types (rbn1 - rbn2 / rbn3...). You can not overload all operators (eg =.[]), and for operators that have opposites you have to overload both (eg < >, == !=). This keeps some sanity, obviously this is a feature you could abuse, but in reality it isn't a big problem. Generally in C# it is possible to define a class that behaves like or extends a built in language feature.

explicit virtual methods 

You have to explicitly mark a method virtual, and then explicitly override it. I think this is what everyone wants, but maybe someone would disagree. Anders Hejlsberg has a great point about how versioning can be a problem when these are left open.

params 

The last parameter of a method can be a special array type called params. This allows for methods that can take a variable number of arguments (of the same type). It is still type safe of course, just the last arguments get converted to an array. This is a huge deal when you need it and can save you some very ugly code.

ref 

Parameters passed with the 'ref' keyword will always be by reference (even for value types), so changes in the method will affect the source variable. For example, int x = 5; Increment(ref x); will result in x being equal to six when the method returns.

out 

Allows the passing of an unassigned variable, and it will come back assigned (it ignores the current value if there is one). This allows multiple return values, basically you just list the values you want assigned as parameters. Such methods can still have the normal return types as well. If you've ever felt methods signatures should include the return type, this is pretty close (you could just always return void, and pass the return type(s) in the parameter list - btw I don't know of it being used like this, just it could).

aliases 

You can import namespaces of course, and you can also give things different names. This is useful in a lot of ways, particularly I find when you have two namespaces that share a lot of names. Say you have two graphics formats, they each have common things like Point, Curve, Line etc. Rather than have to manually write out the whole path each time, you can say
 
 using swf = DDW.Graphic.Format.Swf;
 using emf = DDW.Graphic.Format.Emf;
 
 After this you can say swf.Point or emf.Point with no confusion. Another bonus, the compiler can still catch mistakes if there are a small differences in two imports, like swf.Rect emf.Rectangle (as opposed to saying Rect r = new Rect(), when you actually meant the emf Rectangle).

multiple classes per file 

Not sure why both Java and Actionscript2 disallow this. The C# compiler I made has over 100 classes in one file (one per element type) -- it's called codegen. Find and replace also works much better, if I had to open 100+ files to change a method name I wouldn't bother. Normally I pretty much use one class per file, but why the restriction? Even worse is the mandatory Java directory structure (maybe it isn't like that any more, god I hate that though).

foreach 

Much like it sounds, an easy way to iterate over a collection.

IDisposable/using 

If you have a resource that must be disposed when you are done, then you can just wrap it like so:
 

using (Brush b1 = new Brush("Red"), b2 = new Brush("Blue"))
{
     // use b1 and b2
} // auto el disposo happens here

This can be pretty convenient

is 

I use this all the time, it just checks the actual type:
 if(polygon is Pentagon)...

as 

Casts to a type, but instead of getting an exception on mismatch, you just get null.
 string s = obj as string;
 if(s != null)...

jagged arrays

Arrays of arrays, like int[][]. Arrays can also have 'dimensions', which look like [,,], or both, [,][][,,]. Ten cents to the person who can clearly sum up how these are different and how they are best used, in a paragraph or less.

These are pretty confusing. I'd say something nice about them, but that was a very troublesome thing for me to get right in the parser. Imo a data structure anything like this in code looks pretty flaky, but I could see it in things like remoting, code gen, or serialization. The initializers of things like int[][,][,,] get truly absurd.

verbatim @"strings"

Another sugar feature that I love. Automatic escaped strings, every character except the double quote itself (use two double quotes if you want this). Just say @"C:\dirty\pics". A lesser known feature is you can also use this on variable names to ignore collisions with keywords. For example if you were machine translating an actionscript program to C#, and the code used 'long' for a variable name, you could name it @long. It still results in a token named 'long', just the token is treated as an identifier, not a keyword.

preprocessor directives

These are used for things like conditional compilation, setting things like debug level, defining regions in code (for code folding, nice that this is part of the language spec!), etc. Specifically these:
 
 #if
 #else
 #elif
 #endif
 
 #define
 #undef
 
 #warning
 #error
 #line
 
 #region
 #endregion

posted on Wednesday, May 05, 2004 4:00 AM
Feedback
  • # re: Some somewhat unique C# features somewhat explained
    bokel
    Posted @ 5/5/2004 10:16 AM
    In a jagged array the subarrays can all have different dimensions while in a standard array all the subarrays have the same dimension.

    nice article, though :)
    ralf.

  • # re: Some somewhat unique C# features somewhat explained
    darron
    Posted @ 5/5/2004 10:34 AM
    Nice summary. I really enjoy C# over Java as a language, but I'm drawn to Java because of it's cross-platform support.

    Interestingly enough, the mono project just released beta 1 yesterday. http://www.go-mono.com/

  • # re: Some somewhat unique C# features somewhat explained
    Robin Debreuil
    Posted @ 5/5/2004 3:27 PM
    Well the man gets a dime : ). Nicely said bokel.

    Cool to hear mono went beta1 - Unfortunatly a lot of people seem to use Linux because it isn't associated with Microsoft, so not sure what the pickup will be there ; ). Still, great project, I'm using it anyway!

  • # re: Some somewhat unique C# features somewhat explained
    Bent Rasmussen
    Posted @ 5/7/2004 10:07 AM
    "I really enjoy C# over Java as a language, but I'm drawn to Java because of it's cross-platform support."

    Don't forget that C# is an ECMA standard. That's gotta count for something. It may be that MS controls the future of C#, but at least you can take or leave 1.0.

    "Unfortunatly a lot of people seem to use Linux because it isn't associated with Microsoft"

    Is that a fact? http://www.dotgnu.org/danger.html. :)



  • # re: Some somewhat unique C# features somewhat explained
    Sean
    Posted @ 6/2/2004 12:46 AM
    Its fun when someone puts all the classes into one file, and then your sys admin locks source safe into single user mode, so only one person can be woring on a file.

    Couple that with 100 classes in the file, and 3 developers, and you have a pain in the ass

    Needless to say, the classes soon moved to their own files.

  • # re: Some somewhat unique C# features somewhat explained
    Robin Debreuil
    Posted @ 6/2/2004 1:35 AM
    Uhhh... having multiple classes in one file is an option, not a requirement, sorry if I didn't make that clear. I'm actually currently working on a program (compiler) that includes over 100 similar classes in one file -- not only was the inital code gen easier, but when I want to make a minor change across classes (which has happened a lot) it is one regex and .01 seconds. The option dealing with 100+ files etc etc, which means I probably wouldn't bother. There is also code folding which imo is essential to make this useful.

    Thinking of a situations where this option wouldn't be helpful doesn't really say anything though. 100 nested namespaces, and soon you would move to fewer - sure, but so what?




Blog Stats

  • Posts - 121
  • Stories - 1
  • Comments - 1441
  • Trackbacks - 47

.Net Blogs

01101 Blogs

Flash Blogs

Graphics

People