New CSharp Language features 3.0 and 4.0

From OpenPetra Wiki
Jump to navigation Jump to search

This Page is Work in Progress

The content for this page is being written and not complete yet. Its content should not be relied on at the moment.

For reference only: C# 2.0

Although this wiki page discusses the new language features of C# 3.0 and C# 4.0, it is occasionally helpful to know what language features were introduced in C# 2.0. Lists of those can be found here and here, too. There is a chance you haven't known about one of those language features of C# 2.0 and therefore might not have used it yet... ;-)

New features

C# 3.0

Microsoft's Official 'Overview' of C# 3.0

  • see [1] (Verbose - 38 printed pages!)

External Concise Resources


Implicitly Typed Local Variables (aka 'Local Variable Type Inference')

  • At first glance this feature looks like it does what the 'dreaded' VARIANT Type of Visual Basic 6 does, where it results in late-bound Type Inference which can cause very difficult-to-spot errors at runtime.
  • However, Implicitly Typed Local Variables result in early-bound strongly-typed code, which is way better as its VB 6 'colleague' as it can not cause those errors at run-time!
  • Only works for local variables in a method (that is, not for Class Fields or Method Arguments).
  • Implicitly Typed Local Variables are a 'compiler trick' (and as such work even with the .NET 2.0 Runtime - see [2]) .
  • Usage
    • Use new var keyword for the declaration of such variables.
    • Should not be over-used as the source code is less explicit than when the Type it holds is stated explicitly.
    • Can be a time saver for declaration of long Types, esp. Generic Types; there it fine to be used and actually can result in easier-to-read code.
  • Usage example in OpenPetra source code: none yet.
  • Details: [3]
  • Video: [4] (8:09 minutes)

Auto-implemented Properties (aka 'Automatic Properties')

  • Saves writing code for getters and setters of Properties that simple read and write a Classes' Field.
  • Usage
    • Declare a Property like this: public int TestValue { get; set; }.
      • There is no need to declare a Field named 'TestValue' - this is done automatically by the compiler (hence the name 'auto-implemented Properties').
    • A neat feature, but it results in Class Fields that are named like the Property.
      • This goes against the naming convention for Class Fields in OpenPetra source code: Class Fields always need to start with the letter 'F' (for Field). Reasoning: to make it easier to distinct between local Variables and Class Fields in program code with a quick glance.
      • Alternative: IDEs can usually auto-generate source code for a Property declaration from a Field. All you have to do is to rename the Property to not start with the letter 'F' (for example, in SharpDevelop this automatic code generation is accomplished by choosing 'Create getter' or 'Create Property' from the context menu while the cursor is on a Field {it makes the 'F' start character of the Field's name lowercase, so correct it to uppercase to conform to another naming convention for OpenPetra source code).
  • Auto-implemented Properties are a 'compiler trick' (and as such work even with the .NET 2.0 Runtime - see [5]).
  • Usage example in OpenPetra source code: used already in the web server for the Conference back-end.
  • Details: [6]

Object Initializers

  • Saves writing code to set Properties of newly constructed Objects as this is done in one command at the point of creating the object, rather than in several commands.
  • Object Initializers are a 'compiler trick' (and as such work even with the .NET 2.0 Runtime - see [7]).
  • Usage: see Details below.
  • Usage example in OpenPetra source code: used by ext.net which is used by the web server for conference back-end.
  • Details: [8], [9]
  • Video: [10] (5:26 minutes)

Collection Initializers, Dictionary Initializers

  • Similar to Object Initializers, but for the initialisation of values of Collections or Dictionaries.
  • Collection/Dictionary Initializers are 'compiler tricks' (and as such work even with the .NET 2.0 Runtime - see [11]).
  • Usage: see Details below.
  • Details:
    • Collection Initializers: [12]
      • Video: [13] (4:44 minutes)
    • Dictionary Initializers: [14]

Anonymous Types

  • An Anonymous Type is a compiler-generated, 'on-the-fly'-created Class.
    • They are described by the programmer through the combination of the features of Auto-implemented Properties and Object Initialisers.
    • The Classes of Anonymous Types (and therefore their names) are not visible to the programmer (hence the name 'Anonymous Types'), the programmer can only work with the Object that results of the construction of an Anonymous Type.
    • Anonymous Types are supported only as local Variables.
  • Anonymous Types are a 'compiler trick' (and as such work even with the .NET 2.0 Runtime - see [15]).
  • Usage: see Details below.
  • Usage example in OpenPetra source code: none yet.
  • Details: [16]
  • Video: [17] (17:51 minutes)

Partial Methods

  • Partial Methods complement Partial Classes. They are methods that enable lightweight Event handling.
  • Partial Methods consist of a defining declaration and an optional implementation declaration.
  • The most useful application for the use of Partial Methods lies in code generation, where the code generator can always generate code for Event calls and there might in the end be no implementation for the Event - that is something that is allowed only with Partial Methods.
  • Partial Methods are a 'compiler trick' (and as such work even with the .NET 2.0 Runtime - see [18]). What happens is the following:
    • In case there is no implementation declaration of a Partial Method, then the Compiler will not emit Intermediate Language (IL) to the Assembly for the Event calls and also not for the defining declaration of the Partial Method. Because of the latter, consequently no evaluation of the Method Arguments will occur in the resulting IL (that is not quite obvious as it happens 'behind the scenes').
    • Since this optimisation occurs at compile time, it cannot be used for techniques which require evaluation at runtime, e.g. plug-in scenarios.
  • Partial Methods have some similarity to Conditional Methods, [19], but there are important differences. A good discussion on this can be found in the video mentioned below [20]. The most important distinction is that Conditional Methods rely on compiler directives to be defined, Partial Methods don't (which makes Conditional Methods more suitable for distinction of e.g. DEBUG and RELEASE builds).
  • Rules for Partial Methods
    • Partial Methods must be declared within partial Types - Classes or Structs.
      • That partial Type - Class or Struct - must be declared in the same Assembly than the defining declaration!
    • There must be exactly one defining declaration and - if there is an implementation declaration - then there must be exactly one as well.
    • The defining declaration and the implementation declaration (if there is one) don't have to be in the same part of the Partial Class declaration, but they must be both in the same Partial Class (Reason: Partial Methods must be private).
    • Partial Methods are indicated by the partial modifier.
    • Partial Methods can be static.
    • Partial Methods can be generic.
    • Partial Methods must be private.
    • Partial Methods must return void.
    • Partial Methods can have arguments (including this, ref, and params modifiers) - but no out arguments!
    • Partial Methods do not always have a body.
    • Partial Methods cannot implement interface methods, neither implicitly or explicitly (reason: because they must be private).
  • Usage:
    • If a Partial Method does what you want in a given circumstance, then you should use it instead of an Event, because they are better.
      • Reasons for that:
        • Better performance: Calling a Partial Method simply results in a Method call, and is not using the MS Windows infrastructure to dispatch an Event.
        • Less 'plumbing code' needs to be written (no need for the code that raises the event [On... Methods], no checks needed in those Methods whether there are Event subscribers) --> less Intermediate Language (IL) is emitted to the compiled assemblies.
        • More efficient Intermediate Language (IL) is emitted to the compiled assemblies if Partial Methods aren't implemented, as they are optimised away altogether in that case.
      • Reasons for using Events instead of Partial Methods:
        • Events can be declared in any Class, not just in Partial Classes as is the case with Partial Methods.
        • Events can be declared in an Interface, Partial Methods can't.
        • Events are multicast (0..n subscribers to an Event)
        • Events can have access modifiers (public, ...)
        • Events can be hooked to ('Subscribed to') from any Class, not just the Class where the defining declaration ('Publisher') is found. The Event Handler can again be in a different Class. (This means that the definition, the hooking-up and the Event Handler can be in different assemblies altogether.)
        • Event Subscribers can not only be instance and static Methods as with Partial Methods, but also Anonymous Methods and Lambda Expressions!
        • Events can be hooked to dynamically at runtime (e.g. in plug-in scenarios)
    • More usage guidelines: see the articles in Details section below, and the video that is mentioned below.
  • Usage example in OpenPetra source code:
    • \inc\template\src\Winforms\dynamictabpage_basics.cs: defining declaration of the Partial Method 'partial void PreInitUserControl(UserControl AUserControl);'
    • \inc\template\src\Winforms\dynamictabpage_usercontrol_setup.cs: call to Partial Method 'PreInitUserControl'.
    • \csharp\ICT\Petra\Client\MPartner\Gui\UC_PartnerEdit_PersonnelTabSet.ManualCode.cs: implementation declaration of Partial Method 'PreInitUserControl'.
  • Details: [21], [22] and [23], [24] (the last one is quite in depth, with a lot of short examples, also comparing Partial Methods with Conditional Methods)
    • Video: [25] (15 minutes runtime, recommended)

Extension Methods

  • Extension Methods allow a developer to add Methods (often 'wrapper/helper'-type-of-Methods) to existing Types without creating a new derived Type, recompiling or modifying the original Type’s code. This results in cleaner and easier-to-read source code - neat.
  • Extension Methods are a 'compiler trick' (and as such work even with the .NET 2.0 Runtime - see [26] and (important!) [27]).
  • Rules
    • Extension Methods need to be implemented in static Classes.
    • The this keyword must be placed before an Argument in the implementation of your Extension Method.
    • Extension Methods can access only public members of the Object it is extending from within your Extension Method.
    • Extension methods for Properties are not possible.
  • Usage
    • Import the Namespace where your Extension Method is defined (with the using clause) into the scope where you want to use it. Then simply call the Extension Method on the Object of your choice - which needs to be of the Extension Method's Argument's Type.
    • Caveats:
      • A compiler error will occur if two Namespaces that contain Extensions Methods of the same name are imported into a scope where the Extension Methods should be called.
      • If you add a real Method to the Object that has the same name as the Extension Method then the real Method takes precedence (=the Extension Method is silently ignored).
  • 'Non-usage' :
    • Don't use Extension Methods to achieve what should be achieved with inheritance where inheritance is more applicable.
  • Usage example in OpenPetra source code:
    • \csharp\ICT\Common\Controls\Helper.cs (Method 'FindUserControlOrForm' extends System.Windows.Forms.Control)
  • Details: [28]
  • Video: [29] (15:27 minutes)

Lambda Expressions

  • Lambda Expressions offer a concise way of creating a Delegate and pointing it to a Method, all in one compound statement. They also offer Type Inference which makes writing Lambda Expressions even terser.
  • Lambda Expressions supersede Anonymous Methods, which were new in C# 2.0. Lambda Expressions offer not only nicer syntax, but they offer more than Anonymous Methods as they can be converted into both Delegates and Expression Trees.
  • Lambda Expressions are a 'compiler trick' (and as such work even with the .NET 2.0 Runtime - see [30]).
  • Lambda Expressions utilise the new so-called 'goes to' operator, =>. They can be easily recognised in source code by the presence of this operator.
  • Usage:
    • Lambda Expressions are a more complex language extension, and moreover, feel somewhat unnatural to C# programmers as they are conceptually borrowed from functional programming languages, and that's why I won't go into more detail here. Please see the 'Details' section below for more, watch the videos in that section as well, or search on the Internet for (video) tutorials - there are plenty around.
  • Usage example in OpenPetra source code: none yet.
  • Details: [31] (introductory overview, not complete), [32] (full spec, very detailed)
  • Videos:
    • [33] (13:07 minutes. Good intro, very concise).
    • [34] (11:00 minutes. Good, but some banter at the beginning, gets interesting only from position 1:00 onwards)
    • [35] (12:00 minutes. Expression Trees)

LINQ

  • LINQ stands for ' Language INtegrated Query'. It purports to seamlessly bridge the gap between the object-oriented and the data world. A key in the LINQ concept is that it can be used to access data from various sources, such as objects, collections, XML, or SQL databases.
  • LINQ is a declarative way to query data. So instead of being imperative and using loops and if statements, you can tell C# what you want and LINQ will go ahead and build that data for you.
  • LINQ combines the power of the following C# 3.0 language extensions to provide completely new capabilities to the C# Language: Local Variable Type Inference, Object Initializers, Anonymous Types, Extension Methods, Lambda Expressions and Query Expressions.
  • LINQ introduces a host of new C# keywords like from, where, select, group, orderby, join, and others.
  • Usage:
    • LINQ is a very powerful and rather huge extension to the C# language and it is impossible to cover all the aspects here. Rather, please have a look through the articles linked in the Details section below and view the videos also found there. Also, there is a ton of resources on the Internet on it...
  • Usage example in OpenPetra source code: none yet.
  • Details: [36], [37]
  • Examples - not just for beginners: [38]
  • Videos:
    • [39] (15:03 minutes)
    • [40] (22:02 minutes)
    • [41] (18:08 minutes)

C# 4.0

Optional Parameters

  • A very useful feature that other programming languages (e.g. Visual Basic, Delphi) were offering already for a long time.
  • Looks as it would be one of the more useful features for us.

Named Parameters

  • This goes in hand with Optional Parameters.
  • Looks as it would be one of the more useful features for us, too.

Dynamic Support

  • Advantages:
    • Less casting is needed
    • More readable code.
  • Weaknesses:
    • Compile-time checks are not possible as 'dynamic' uses late-binding.
    • Run-time penalty as .NET Reflection needs to kick in 'under the hood' in cases where plain CLR objects are dealt with.
    • Potential for 'over use' by undiscerning programmers who might use 'dynamic' where 'dynamic' shouldn't be used as it is unnecessary, leading to late-binding (and therefore no compiler checks), which could easily be avoided.
  • Verdict: Could be interesting, mainly where we use .NET Reflection anyway.

Variance

COM Interop

  • Allows for much neater interaction with COM Objects than before, with less coding overhead and explicit type use instead of object types that were needed until this feature was introduced.
  • Probably not interesting for us as the OpenPetra Client should stay platform-independent (COM is available only on Windows OS's!).
    • Could potentially be useful for optional plug-ins for the OpenPetra Client that would need COM to fulfill their roles, though. Obviously those plug-ins would work on only Windows OS's then.

Mono and new C# features

  • Mono 2.6.7 supports C# 3.0
  • Mono 2.8 and greater support C# 4.0
  • The latest Ubuntu version comes with Mono 2.10. The Ubuntu LTS still is using 2.6.7
  • There are 2.10 packages for RedHat/CentOS