C# Language changes from .NET Beta 1 to .NET Beta 2

Changes that might require source code modification 

  • The compiler now enforces the rule requiring the last clause of a switch statement to end with a break, return, throw, or similar statement. Previously, the compiler enforced this rule for all clauses of a switch statement except the last one, contrary to the language reference.

  • It is now illegal to have two method overloads that differ only by having a parameter mode that is ref instead of out

  • The index variable of a foreach statement can no longer be assigned to, as specified in the language reference.

  • Setting a property on a non-variable of struct type is now an error, as specified in the language reference. Such a property set would not have a useful effect. Getting a property is still allowed.

  • The semantics for determining when static field initializers are run are relaxed. If a static constructor is not present, static field initializers might run earlier than they did before. Use a static constructor to use the old precise semantics. 

  • Some small holes in unmanaged code are plugged and the syntax of the fixed statement is slightly tightened in some cases. 

  • Unknown rank arrays (such as int[?]) are no longer supported by the compiler in any way.

  • Backtick quoted strings (such as $hello$) are no longer supported. Use @"hello" instead.

  • Using unsafe as a statement is no longer supported. Place unsafe as a modifier on the method or property instead. 

  • A bug was fixed where the compiler was not generating errors for casts of constant values that overflow at compile time. This might require adding the keyword checked in some places. 

  • Modifiers on property accessors (get or set) are no longer supported. The modifiers (such as virtual) must be placed on the property declaration itself. A tool can help make this change automatically. 

  • The syntax for events that use a get or set accessor is no longer supported. Code should now use add and remove accessors that contain the code for adding or removing a delegate (implicitly named value) to the list of event sinks. 

  • A delegate with a pointer parameter must be declared with the unsafe modifier. 

  • Performing a cast that can never succeed with the as operator now generates an error, just as with the normal cast operator. Previously, this was only a warning. 

  • The compiler now correctly assumes that a library without a CLSCompliant attribute is non-compliant. Previously, the compiler assumed that a library without the attribute was compliant.

  • Arrays of arrays are no longer considered CLS-compliant types. 

  • Attribute target specifiers have been added. In certain cases, the location of an attribute is insufficient to determine which item the attribute refers to. For example, an attribute immediately before a method might refer to the method or only to the return value of the method. In such a case, C# now allows a target specifier on the attribute that indicates what the attribute is intended for. Without the target specifier, the attribute is assumed to apply to the primary item that follows the attribute. The complete list of target override specifiers is assembly, module, type, method, property, field, param, event, and return. This will require code changes for marshaling attributes applied to the return value of a method. What was previously written as:

           [MarshalAs(...)] string testString()
           must now be written as

           [return:MarshalAs(...)] string testString()

  • Old attribute forms are no longer allowed. C# previously allowed various attributes to be specified that were not actually attribute classes in the base class libraries. These forms are no longer allowed and they must be translated to the actual attribute classes as shown in the following table. (In the table, the final "Attribute" on the class has been omitted, as it would be in C# code).


Previous Form  New Form
attributeusage  System.AttributeUsage
comimport  System.Runtime.InteropServices.ComImport
commethod  No direct mapping. Use System.Runtime.InteropServices.PreserveSig for similar functionality.
conditional  System.Diagnostics.Conditional
dispid  System.Runtime.InteropServices.DispId
dllimport  System.Runtime.InteropServices.DllImport
guid System.Runtime.InteropServices.Guid
in  System.Runtime.InteropServices.In 
interfacetype  System.Runtime.InteropServices.InterfaceType
marshal  System.Runtime.InteropServices.MarshalAs
name  System.Runtime.CompilerServices.CSharp.IndexerName
nativetype  No direct mapping. Use System.Runtime.InteropServices.MarshalAs for similar functionality. 
nonserialized  System.NonSerialized
obsolete  System.Obsolete 
out  System.Runtime.InteropServices.Out
Nno direct mapping. Use System.Runtime.InteropServices.PreserveSig or the PreserveSig argument on DllImport for similar functionality
serializable  System.Serializable
structlayout  System.Runtime.InteropServices.StructLayout 
structoffset  System.Runtime.InteropServices.FieldOffset
sysimport  System.Runtime.InteropServices.DllImport
sysstruct  No direct mapping. Use System.Runtime.InteropServices.StructLayout for similar functionality.
uuid  System.Runtime.InteropServices.Guid

New language features

  • The using statement is now supported.

  • The sealed modifier can now be used in conjunction with the override modifier on a method to prevent any further overriding of a method.

  • Events can now be marked as virtual, abstract, or override.

  •  A virtual member can now be overridden by an abstract member.

  •  XML comments can now use <include> directives to allow XML documentation to be retrieved from another file.

  • C# allows eight-digit Unicode escapes of the form \Unnnnnnnn .("U" is uppercase for this form).

Changes that might require build changes

  • The /nooutput compiler option is no longer supported.

  • Using unsafe language features now requires the /unsafe compiler option to be specified. 

  • Several command-line options were deprecated and removed. The following table lists the deprecated items and their new equivalents.

Deprecated command-line option  New equivalent command-line option
/assemble-  /target:module
/dll /target:library
/dllbase /baseaddress
/exe  /target:exe
/import  /reference
/winexe  /target:winexe 

  • The following command-line options involving assembly manifests are deprecated in favor of using assembly-level attributes in the source code. These options still work (with a warning) for this integration, but will be removed in the next integration. The following table lists the options and their new attribute equivalents.

Command-line options  Assembly-level attribute equivalent
/a.config  System.Reflection.AssemblyConfiguration 
/a.culture  System.Runtime.CompilerServices.AssemblyCulture
/a.description  System.Reflection.AssemblyDescription
/a.keyfile  System.Runtime.CompilerServices.AssemblyKeyFile
/a.keyname  System.Runtime.CompilerServices.AssemblyKeyName
/a.sign  System.Runtime.CompilerServices.AssemblyDelaySign
/a.title  System.Reflection.AssemblyTitle 
/a.version System.Runtime.CompilerServices.AssemblyVersion 

  • The search mechanism for references that are not fully qualified paths has changed. The new search mechanism is as follows:

1) Current working directory.  This is the directory the user is running the compiler from.

2) COM+ system directory retrieved from GetCorSystemDirectory() using the shim.

3) /LIB command-line option.

4) LIB environment variable.

Changes that are not likely to require source code changes, except in very obscure cases

  • The compiler now generates code that produces a NullReferenceException when calling a non-virtual instance method on null, even if that method never uses this. Previously, a NullReferenceException was only generated if the called method attempted to dereference this.

  • The compiler now respects the C++ hide-by-name overloading semantics. When calling an overloaded method on a class emitted by C++, the compiler only resolves overloads among methods at a single derivation level.

  • CLS checking now prohibits two methods that differ only in the ref or out modifiers on a parameter. 

  • The compiler-generated static constructor is now always private.

  • The command-line compiler now has some extra ways to specify command-line arguments (such as references):

1. The file csc.rsp in the directory containing csc.exe is always read for command-line arguments as if it were a response file.

2. The file csc.rsp in the current directory is always read for command-line arguments as if it were a response file.

New warnings 

  • Use of a lowercase 'l' suffix on an integral constant will produce a warning suggesting use of an uppercase 'L' for clarity. This is because 'l' and '1' look similar.

  • The compiler now generates a warning if it is possible that members of System.Object that should be overloaded are not. Specifically, if you override Object.Equals(), you should also override Object.GetHashCode(). In addition, if you define == and !=, you should override Object.Equals() and Object.GetHashCode().

  • A warning is generated if a publicly exposed member that does not have an XML comment is producing XML documentation.