Top Banner
Category:Exam 70-536 Study Guide: Skill Set 1 Microsoft .NET Framework, ASP.NET, Visual C# (CSharp, C Sharp, C-Sharp) Developer Training, Visual Studio Articles in category "Exam 70-536 Study Guide: Skill Set 1" There are 52 articles in this category. ArrayList Attributes BitArray class Boxing and Unboxing Class Members Collection interfaces CollectionBase classes Comparer class Constructors and Destructors Copy Constructors Declaring Classes Delegate DictionaryBase classes Event Exam 70-536 Study Guide: Skill Set 1 Exception classes Fields and Properties Generic Lists Generic Queue Generic Stack Generic interfaces Generic types Hashtable class ICloneable IComparable IConvertible IDisposable IEquatable IFormattable INullableValue Implement .NET Framework interfaces Interfaces and Abstract Classes Iterators Manage a group of associated data using collections Manage data in a .NET Framework application
125

70-536 test part 1

Nov 17, 2014

Download

Documents

api-26796793
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: 70-536 test part 1

Category:Exam 70-536 Study Guide: Skill Set 1Microsoft .NET Framework, ASP.NET, Visual C# (CSharp, C Sharp, C-Sharp) Developer Training, Visual Studio

Articles in category "Exam 70-536 Study Guide: Skill Set 1"There are 52 articles in this category.

ArrayList Attributes BitArray class Boxing and Unboxing Class Members Collection interfaces CollectionBase classes Comparer class Constructors and Destructors Copy Constructors Declaring Classes Delegate DictionaryBase classes Event Exam 70-536 Study Guide: Skill Set 1 Exception classes Fields and Properties Generic Lists Generic Queue Generic Stack Generic interfaces Generic types Hashtable class ICloneable IComparable IConvertible IDisposable IEquatable IFormattable INullableValue Implement .NET Framework interfaces Interfaces and Abstract Classes Iterators Manage a group of associated data using collections Manage data in a .NET Framework application Nested Classes Nullable type Queue class Reference types SortedList class Stack class Template:Exam 70-536 Study Guide Skill Set 1-4

Page 2: 70-536 test part 1

TypeForwardedToAttribute Typecasting Use events and delegates Use generic collections Use specialized collections Value types Value vs Reference const, static and readonly enum struct

ArrayList

Description An ArrayList is an array that can dynamically grow and shrink.

Members Here are some of the common members of the ArrayList class. For a complete listing see the MSDN Reference at the bottom of the page.

Properties Capacity - Gets or sets the number of elements that the ArrayList can contain. Count - Gets the number of elements contained in an ArrayList object. IsFixedSize - Gets a value indicating whether a ArrayList object has a fixed size. A collection with a fixed size does not allow the addition or removal of elements after the collection is created, but does allow the modification of existing elements. Item - Gets or sets the element at the specified index. Methods Add(value) - Adds an object to the end of the ArrayList.

Yep Because the ArrayList is untyped, you should use List<T> unless backwards compatibility is needed.

Code Examples Using an arraylist to store numbers // Create a new ArrayListArrayList numbers = new ArrayList(); // Add some numbers to the listnumbers.Add( 7 );numbers.Add( 21 ); // Get the numbers out of the list// Notice a cast is required because// ArrayList only contain objects (untyped)// This also performs an unboxing operationint numA = (int)numbers[0];int numB = (int)numbers[1];

Page 3: 70-536 test part 1

Bad example of mixing the content of an ArrayList // Create a new ArrayListArrayList mixedList = new ArrayList(); // Add some numbers to the listmixedList.Add( 7 );mixedList.Add( 21 ); // Add some strings to the listmixedList.Add( "Hello" );mixedList.Add( "This is going to be a problem" ); // Now try to iterate the list// This will throw an exceptionforeach( string text in mixedList){ //...}

ArrayList Class

Implements the IList interface using an array whose size is dynamically increased as required.

Namespace: System.CollectionsAssembly: mscorlib (in mscorlib.dll)

C#[SerializableAttribute][ComVisibleAttribute(true)]public class ArrayList : IList, ICollection, IEnumerable, ICloneable

The following code example shows how to create and initialize an ArrayList and how to print out its values.

vbImports SystemImports System.CollectionsImports Microsoft.VisualBasicPublic Class SamplesArrayList Public Shared Sub Main()' Creates and initializes a new ArrayList.Dim myAL As New ArrayList()myAL.Add("Hello")myAL.Add("World")myAL.Add("!")'Displays the properties and values of the ArrayList.Console.WriteLine("myAL")

Page 4: 70-536 test part 1

Console.WriteLine(" Count: {0}", myAL.Count)Console.WriteLine(" Capacity: {0}", myAL.Capacity)Console.Write(" Values:")PrintValues(myAL)End SubPublic Shared Sub PrintValues(myList As IEnumerable)Dim obj As [Object]For Each obj In myListConsole.Write(" {0}", obj)Next objConsole.WriteLine()End Sub 'PrintValuesEnd Class

‘This code produces output similar to the following:' ‘myAL' Count: 3' Capacity: 4' Values: Hello World !c#using System;using System.Collections;public class SamplesArrayList {

public static void Main() {

// Creates and initializes a new ArrayList. ArrayList myAL = new ArrayList(); myAL.Add("Hello"); myAL.Add("World"); myAL.Add("!");

// Displays the properties and values of the ArrayList. Console.WriteLine( "myAL" ); Console.WriteLine( " Count: {0}", myAL.Count ); Console.WriteLine( " Capacity: {0}", myAL.Capacity ); Console.Write( " Values:" ); PrintValues( myAL ); } public static void PrintValues( IEnumerable myList ) { foreach ( Object obj in myList ) Console.Write( " {0}", obj ); Console.WriteLine(); }}

/* This code produces output similar to the following:

Page 5: 70-536 test part 1

myAL Count: 3 Capacity: f Values: Hello World !

*/

AttributesAn attribute is a mechanism to add declarative information to code elements (types, members, assemblies or modules) beyond the usual predefined keywords. They are saved with the metadata of the object and can be used to describe the code at runtime or to affect application behavior at run time through the use of reflection.

An attribute must derive from the System.Attribute class, either directly or indirectly. This means that as well as the numerous predefined attributes that are in the .NET FCL, you can define your own custom attributes.

Attribute usage and syntaxThe convention of adding the suffix "Attribute" to all attribute names is adopted to distinguish them from other items in the .NET Framework. However, it is not necessary to specify the attribute suffix when using attributes in code. For example, [DllImport] is equivalent to using [System.DllImportAttribute], but DllImportAttribute is the attribute's actual name in the System namespace of the .NET Framework.

Attributes can be placed on almost any target element (though a specific attribute might restrict the types of declarations on which it is valid). Syntactically, an attribute is specified by placing the name of the attribute, enclosed in square brackets, in front of the declaration of the entity to which it applies. For example, a method with the attribute DllImport is declared like this:

[DllImport("cards.dll")]public static extern bool cdtInit (ref int width, ref int height );Where "cards.dll" is the name of the dll that is being imported into the application and cdtInit is the name of the method within the dll.

Positional parameters Positional parameters are specified first. Any positional parameters must be specified in a certain order and cannot be omitted. For example, if we look at the method above, there is one specified parameter which is the name of the dll file.

Positional parameters are defined in the constructor of the class, so in this instance, the constructor of the DllImport attribute looks like this:

public DllImportAttribute ( string dllName ){ // ...}

Page 6: 70-536 test part 1

Named parameters Named parameters are optional and can be specified in any order after any positional parameters. These are defined as public properties in the class. If we take a look at a couple of the properties of the DllImportAttribute class, we can show this in action.

SetLastError - Indicates whether the callee calls the SetLastError Win32 API function before returning from the attributed method. EntryPoint - Indicates the name or ordinal of the DLL entry point to be called. For example, calling the Beep method located in "kernel32.dll" may look like this:

[DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "Beep")]static extern Boolean Beep(UInt32 frequency, UInt32 duration);The positional property is specified first with the two named parameters following it. Equally the attributes could look like this:

[DllImport("Kernel32.dll", EntryPoint = "Beep", SetLastError = true)]static extern Boolean Beep(UInt32 frequency, UInt32 duration);This is equally as valid as the first example. The positional property is specified first with the two named parameters following it.

Using multiple attributes More than one attribute can be associated with an element if it is required. There are two methods of implementing this, stacking or combining. Here is an example of stacking two attributes:

bool aMethod([In][Out]ref double x);And here is an example of combining the same two attributes:

bool aMethod([In,Out]ref double x);Target type In certain situations, the target of an attribute (that is, the entity to which the attribute applies) appears to be ambiguous. Usually, the type that immediately follows the attribute declaration is what the attribute is assigned to, so there is no need to supply the target. However, you may want to assign the target in your attribute declaration for clarity and readability. For example, in the following method declaration, the SomeAttribute attribute could apply to the method or to the methods return value:

[SomeAttribute("Hello")]public string MyMethod(string aString){return aString;} This sort of situation arises frequently when marshalling. To resolve the ambiguity, C# has a set of default targets for each kind of declaration, which can be overridden by explicitly specifying attribute targets.

[method: SomeAttribute] // applies to methodpublic string MyMethod(string aString) [return: SomeAttribute] // applies to return value

Page 7: 70-536 test part 1

public string MyMethod(string aString) [SomeAttribute] // default: applies to methodpublic string MyMethod(string aString)Note that this is independent of the targets on which SomeAttribute is defined to be valid; that is, even if SomeAttribute were defined to apply only to return values, the return target would still have to be specified. In other words, the compiler will not use AttributeUsage information to resolve ambiguous attribute targets.

The syntax for attribute targets is as follows:

[Target: attribute list]The table below lists all declarations where attributes are allowed; for each declaration, the possible targets for attributes on the declaration are listed in the second column. The targets in bold are the default values.

Declaration Possible Targets assembly assembly module module class type struct type interface type enum type delegate type, return method method, return parameter param field field property —indexer property property — get accessor method, return property — set accessor method, param, return event — field event, field, method event — property event, property event — add method, param event — remove method, param Predefined attributes The .NET Framework comes with almost 200 predefined attributes, used for purposes such as debugging, design-time, compiler/runtime control behavior, and much more. The following are some of the more common predefined attributes:

Predefined .NET Attribute

Valid Targets Description

AttributeUsage Class Specifies the valid usage of another attribute class.

CLSCompliant All Indicates whether a program element is compliant with the Common Language Specification (CLS).

Conditional Method Indicates that the compiler can ignore any calls to this method if the

Page 8: 70-536 test part 1

associated string is defined.

DllImport Method Specifies the DLL location that contains the implementation of an external method.

MTAThread Method (Main) Indicates that the default threading model for an application is multithreaded apartment (MTA).

NonSerialized Field Applies to fields of a class flagged as Serializable; specifies that these fields won’t be serialized.

Obsolete All except Assembly, Module, Parameter, and Return

Marks an element obsolete—in other words, it informs the user that the element will be removed in future versions of the product.

ParamArray Parameter Allows a single parameter to be implicitly treated as a params (array) parameter.

Serializable Class, struct, enum, delegate

Specifies that all public and private fields of this type can be serialized.

STAThread Method (Main) Indicates that the default threading model for an application is STA.

StructLayout Class, struct Specifies the nature of the data layout of a class or struct, such as Auto, Explicit, or Sequential.

ThreadStatic Field (static) Implements thread-local storage (TLS)—in other words, the given static field isn’t shared across multiple threads and each thread has its own copy of the static field.

Custom attributes You can create custom attributes to add extra information to your code.

Creating a Custom Attribute Class Each attribute is extended from the System.Attribute class. System.Attribute is an abstract class defining the intrinsic services of an attribute. The MSDN documentation gives an example for creating an Author attribute, so that the author of a piece of code can be recorded.

[System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Struct)]public class AuthorAttribute : System.Attribute{

Page 9: 70-536 test part 1

private string name; public double version; public AuthorAttribute(string name) { this.name = name; version = 1.0; }} When using the attribute, the code:

[Author ("H. Ackerman", version = 1.1)]class SampleClassis conceptually equivalent to this:

AuthorAttribute anonymousAuthorObject = new AuthorAttribute("H. Ackerman");anonymousAuthorObject.version = 1.1;class SampleClass The sample class code is simply supplied in the MSDN article without much explanation but let’s look at what each part of the code does.

Assigning the AttributeUsageAttribute to your class When you are defining your own attribute class, you can control the manner in which it is used by placing an AttributeUsageAttribute on your attribute class. The supplied code shows the shortened version of the class name (as discussed at the beginning of this section), with the inclusion on the namespace. The namespace is not needed if you include "using System;

AttributeUsage has three parameters: ValidOn, AllowMultiple and Inherited. The ValidOn parameter is positional and accepts values from the AttributeTargets enumerator. This parameter is used to restrict the use of your attribute to the code types you specify. The default value is AttributeTargets.All, but you can combine several AttributeTargets values using a bitwise OR operation to get the desired combination of valid program elements. The members of AttributeTargets enum are:

All - Attribute can be applied to any application element. Assembly - Attribute can be applied to an assembly. Class - Attribute can be applied to a class. Constructor - Attribute can be applied to a constructor. Delegate - Attribute can be applied to a delegate. Enum - Attribute can be applied to an enumeration. Event - Attribute can be applied to an event. Field - Attribute can be applied to a field. GenericParameter - Attribute can be applied to a generic parameter. Interface - Attribute can be applied to an interface. Method - Attribute can be applied to a method. Module - Attribute can be applied to a module (.exe or .dll). Parameter - Attribute can be applied to a parameter. Property - Attribute can be applied to a property. ReturnValue - Attribute can be applied to a return value. Struct - Attribute can be applied to a structure; that is, a value type. * Reference AttributeTargets Enumeration (MSDN)

Page 10: 70-536 test part 1

The sample above (AuthorAttribute) indicates that the attribute can be applied to classes and structures only.

AllowMultiple is a named parameter which specifies whether the indicated attribute can be specified more than once for a given program element. The default value is false. To allow the above sample to be used more than once, this parameter needs to be set to true.

[System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Struct, AllowMultiple = true) // multiuse attribute] The sample in the MSDN article can be seen in use thus:

[Author ("H. Ackerman", version = 1.1)][Author ("M. Knott", version = 1.2)]class SampleClass{ // H. Ackerman's code goes here... // M. Knott's code goes here...} Inherited is a named parameter which specifies whether the indicated attribute can be inherited by derived classes and overriding members. The default value is true.

Creating positional parameters Positional parameters are defined in the constructor of the class. So in the MSDN sample class, there is one positional parameter called name which is passed in as a parameter to the constructor of the class.

Creating named parameters Named parameters are defined as public fields or properties in the class. So in the MSDN sample class, there is one named parameter called version. Reflecting on attributes Once you have mastered the ability of creating attributes, it is useful to use them in the code. This can be achieved through the use of the GetCustomAttributes method of the Attributes class.

The GetCustomAttributes method returns an array of Attribute objects. As the AuthorAttribute has AllowMultiple set to true, it is possible to define the same attribute multiple times on an element. Also, not all elements will have the attribute defined that is being searching for, so GetCustomAttributes can return an array with multiple results, or an empty array.

In order to return all of the attributes members, the AuthorAttribute class needs a small modification to return the positional parameter.

public string Name{get { return name; }} The GetCustomAttributes method has many variations, see MSDN for more information. In order to get all attributes attached to a type, only one argument is required. This is a

Page 11: 70-536 test part 1

boolean value telling the framework whether it should look at the types that this class derives from.

Here is a sample Console application that uses the AuthorAttribute class.

[Author("J.R.R. Tolkein")]public class FirstClass{}[Author("R. Feist")][Author("J. Herbert", version = 2.0)][Author("P. Martin", version = 2.1)]public class SecondClass{}// No Author attributepublic class ThirdClass{} class Program{ static void Main(string[] args) { PrintAuthorInfo(typeof(FirstClass)); PrintAuthorInfo(typeof(SecondClass)); PrintAuthorInfo(typeof(ThirdClass)); } private static void PrintAuthorInfo(System.Type t) { System.Console.WriteLine("Author information for {0}", t); object[] attrs = t.GetCustomAttributes(false); // reflection foreach (AuthorAttribute a in attrs) { Console.WriteLine("{0}, version {1:f}", a.Name, a.version); } }}The PrintAuthorInfo method uses reflection to obtain the parameters of the AuthorAttribute.

BitArray class

Description The BitArray class manages a compact array of bit values. These bit values are boolean in nature, having the value true (1) or false (0).

Page 12: 70-536 test part 1

Members Here are some of the common members of the BitArray class. For a complete listing see the MSDN Reference at the bottom of the page.

Properties Count - Gets the number of elements contained in the BitArray. IsReadOnly - Gets a value indicating whether the BitArray is read-only. Item - Gets or sets the value of the bit at a specific position in the BitArray. Length - Gets or sets the number of elements in the BitArray. [edit]Methods And(BitArray) - Performs the bitwise AND operation on the elements in the current BitArray against the corresponding elements in the specified BitArray. CopyTo(Array,index) - Copies the entire BitArray to a compatible one-dimensional Array, starting at the specified index of the target array. Get(position) - Gets the value of the bit at a specific position in the BitArray. Not() - Inverts all the bit values in the current BitArray, so that elements set to true are changed to false, and elements set to false are changed to true. Or(BitArray) - Performs the bitwise OR operation on the elements in the current BitArray against the corresponding elements in the specified BitArray. Set(position,value) - Sets the bit at a specific position in the BitArray to the specified value. SetAll(value) - Sets all bits in the BitArray to the specified value. Xor(BitArray) - Performs the bitwise exclusive OR operation on the elements in the current BitArrayagainst the corresponding elements in the specified BitArray.

Size and Indexing The size of a BitArray is set implicitly or explicitly when you create a new one, or by altering its Length property. If you shorten a BitArray, bits are truncated from the high-order end. If you lengthen a BitArray, false bits are added to the high-order end.

Elements in a BitArray are accessed using an integer index, which is zero-based. If you try to index past the end of the BitArray, an ArgumentException is thrown.

Code Examples Creating BitArrays BitArray myBitArray = new BitArray( 5 );Creates a BitArray of length 5 with all values set to false. BitArray myBitArray = new BitArray( 5, false );Creates a BitArray of length 5 with all values set to false. BitArray myBitArray = new BitArray( 5, true );Creates a BitArray of length 5 with all values set to true. byte[] myBytes = new byte[5] { 1, 2, 3, 4, 5 };BitArray myBitArray = new BitArray( myBytes );Creates a BitArray of length 40 with bit pattern equal to the binary equivalent of each number in the byte array (8 bits per byte). bool[] myBools = new bool[5] { true, false, true, true, false };BitArray myBitArray = new BitArray( myBools );Creates a BitArray of length 5 with bit pattern equal to the bool array. int[] myInts = new int[5] { 6, 7, 8, 9, 10 };BitArray myBitArray = new BitArray( myInts );Creates a BitArray of length 160 with bit pattern equal to the binary equivalent of each number in the int array (32 bits per int).

Page 13: 70-536 test part 1

Set Value - Convert value to BitArray Most of the time when using the BitArray class, you simply want to set a value. On initialization this can be done with.

byte[] value = {0x11};BitArray myBits = new BitArray(value);But how can the value be changed later in the code? Unfortunately no method exists in the BitArray class to do this. Therefore you must implement your own method such as the following:

BitArray myBits = new BitArray(8); //define the size //setting a valuefor (byte x = 0; x < myBits.Count; x++){ myBits[x] = (((value >> x) & 0x01) == 0x01) ? true : false;}This type of code can be done in many convoluted ways. The use of a shift operation, bit mask operation and short hand if statement simplify this into just 2 easily understandable lines of code.

Get Value - Convert BitArray to value Another missing feature of the BitArray class is to get the value of the array.

byte value = 0x00; for (byte x = 0; x < bArray.Count; x++){ value |= (byte) ((bArray[x] == true) ? (0x01 << x) : 0x00);}

BitArray Class

Manages a compact array of bit values, which are represented as Booleans, where true indicates that the bit is on (1) and false indicates the bit is off (0).

Namespace: System.CollectionsAssembly: mscorlib (in mscorlib.dll)

Syntax:C#[SerializableAttribute][ComVisibleAttribute(true)]public sealed class BitArray : ICollection, IEnumerable, ICloneable

Examples The following code example shows how to create and initialize a BitArray and how to print out its values.

Page 14: 70-536 test part 1

using System;using System.Collections;public class SamplesBitArray {

public static void Main() {

// Creates and initializes several BitArrays. BitArray myBA1 = new BitArray( 5 );

BitArray myBA2 = new BitArray( 5, false );

byte[] myBytes = new byte[5] { 1, 2, 3, 4, 5 }; BitArray myBA3 = new BitArray( myBytes );

bool[] myBools = new bool[5] { true, false, true, true, false }; BitArray myBA4 = new BitArray( myBools );

int[] myInts = new int[5] { 6, 7, 8, 9, 10 }; BitArray myBA5 = new BitArray( myInts );

// Displays the properties and values of the BitArrays. Console.WriteLine( "myBA1" ); Console.WriteLine( " Count: {0}", myBA1.Count ); Console.WriteLine( " Length: {0}", myBA1.Length ); Console.WriteLine( " Values:" ); PrintValues( myBA1, 8 );

Console.WriteLine( "myBA2" ); Console.WriteLine( " Count: {0}", myBA2.Count ); Console.WriteLine( " Length: {0}", myBA2.Length ); Console.WriteLine( " Values:" ); PrintValues( myBA2, 8 );

Console.WriteLine( "myBA3" ); Console.WriteLine( " Count: {0}", myBA3.Count ); Console.WriteLine( " Length: {0}", myBA3.Length ); Console.WriteLine( " Values:" ); PrintValues( myBA3, 8 );

Console.WriteLine( "myBA4" ); Console.WriteLine( " Count: {0}", myBA4.Count ); Console.WriteLine( " Length: {0}", myBA4.Length ); Console.WriteLine( " Values:" ); PrintValues( myBA4, 8 );

Console.WriteLine( "myBA5" ); Console.WriteLine( " Count: {0}", myBA5.Count ); Console.WriteLine( " Length: {0}", myBA5.Length ); Console.WriteLine( " Values:" );

Page 15: 70-536 test part 1

PrintValues( myBA5, 8 ); }

public static void PrintValues( IEnumerable myList, int myWidth ) { int i = myWidth; foreach ( Object obj in myList ) { if ( i <= 0 ) { i = myWidth; Console.WriteLine(); } i--; Console.Write( "{0,8}", obj ); } Console.WriteLine(); }

}

/* This code produces the following output.

myBA1 Count: 5 Length: 5 Values: False False False False FalsemyBA2 Count: 5 Length: 5 Values: False False False False FalsemyBA3 Count: 40 Length: 40 Values: True False False False False False False False False True False False False False False False True True False False False False False False False False True False False False False False True False True False False False False FalsemyBA4 Count: 5 Length: 5 Values: True False True True FalsemyBA5 Count: 160 Length: 160

Page 16: 70-536 test part 1

Values: False True True False False False False False False False False False False False False False False False False False False False False False False False False False False False False False True True True False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False False True False False False False False False False False False False False False False False False False False False False False False False False False False False False False True False False True False False False False False False False False False False False False False False False False False False False False False False False False False False False False False True False True False False False False False False False False False False False False False False False False False False False False False False False False False False False False*/

Inheritance Hierarchy System..::.ObjectSystem.Collections..::.BitArray

Thread Safety Public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe. This implementation does not provide a synchronized (thread safe) wrapper for a BitArray. Enumerating through a collection is intrinsically not a thread-safe procedure. Even when a collection is synchronized, other threads can still modify the collection, which causes the enumerator to throw an exception. To guarantee thread safety during enumeration, you can either lock the collection during the entire enumeration or catch the exceptions resulting from changes made by other threads.

BitArray MembersManages a compact array of bit values, which are represented as Booleans, where true indicates that the bit is on (1) and false indicates the bit is off (0). The BitArray type exposes the following members.

Constructors Name Description BitArray Overloaded. Initializes a new instance of the BitArray class whose capacity and

initial values can be specified.

Methods Name Description

Page 17: 70-536 test part 1

And Performs the bitwise AND operation on the elements in the current BitArray against the corresponding elements in the specified BitArray.

Clone Creates a shallow copy of the BitArray. CopyTo Copies the entire BitArray to a compatible one-dimensional Array,

starting at the specified index of the target array. Equals Determines whether the specified Object is equal to the current

Object. (Inherited from Object.) Finalize Allows an Object to attempt to free resources and perform other

cleanup operations before the Object is reclaimed by garbage collection. (Inherited from Object.)

Get Gets the value of the bit at a specific position in the BitArray. GetEnumerator Returns an enumerator that iterates through the BitArray. GetHashCode Serves as a hash function for a particular type. (Inherited from

Object.) GetType Gets the Type of the current instance. (Inherited from Object.) MemberwiseClone Creates a shallow copy of the current Object. (Inherited from Object.) Not Inverts all the bit values in the current BitArray, so that elements set

to true are changed to false, and elements set to false are changed to true.

Or Performs the bitwise OR operation on the elements in the current BitArray against the corresponding elements in the specified BitArray.

Set Sets the bit at a specific position in the BitArray to the specified value. SetAll Sets all bits in the BitArray to the specified value. ToString Returns a String that represents the current Object. (Inherited from

Object.) Xor Performs the bitwise exclusive OR operation on the elements in the

current BitArray against the corresponding elements in the specified BitArray.

Extension Methods Name Description AsQueryable Converts an IEnumerable to an IQueryable. (Defined by Queryable.) Cast Converts the elements of an IEnumerable to the specified type.

(Defined by Enumerable.) OfType Filters the elements of an IEnumerable based on a specified type. (Defined

by Enumerable.)

PropertiesName Description Count Gets the number of elements contained in the BitArray. IsReadOnly Gets a value indicating whether the BitArray is read-only. IsSynchronized Gets a value indicating whether access to the BitArray is synchronized

(thread safe). Item Gets or sets the value of the bit at a specific position in the BitArray. Length Gets or sets the number of elements in the BitArray. SyncRoot Gets an object that can be used to synchronize access to the BitArray.

Page 18: 70-536 test part 1

Boxing and UnboxingBoxing is the process of turning a value type object into a reference type object. Whenever a value type object is boxed, its value is copied into a new object on the heap and the reference to that object is stored.

int number = 10; // The following causes a box operation// numRef will refer to an object on the // heap which contains a copy of number (10)object numRef = number; // Next unbox the value by casting it to // the appropriate typeint numberB = (int) numRef;

Unboxing is not type safe. It requires a cast because the compiler cannot determine the type of the object. If the object is not the correct type, it will cause an exception during the cast operation. Large numbers of boxing and unboxing operations can become a performance problem. It should be avoided if possible. In particular, Generic types do not depend on boxing operations and they should be used whenever possible. Also, generic types maintain type safety.

Class MembersOnce a class is created it must be populated with data and methods in order to make it useful as a programming construct. The data and methods which act upon the data are referred to as members.

Members There are several types of members that a class can have. These are:

Fields - instances of objects that are considered part of a class, normally holding class data. Properties - methods on a class that are accessed as if they were fields on that class. A property can provide protection for a class field to keep it from being changed without the object's knowledge. For a more detailed understanding see Fields and Properties. Methods - these define the actions that a class can perform by actioning a series of statements. Methods can take parameters that provide input data, and can return output data through parameters. Methods can also return a value directly, without using a parameter. Events - a way of providing notifications about occurrences, such as button clicks or the successful completion of a method, to other objects. Events are defined and triggered using delegates. (See the 70-536 entry for Events and check out the article by Jeff Sudeth and read the sample chapter "Delegates and Events" by Jesse Liberty). Delegates - a type safe container of one or more function pointers. (See the 70-536 entry for Delegates and check out the article by Jeff Sudeth).

Page 19: 70-536 test part 1

Operators - these are terms or symbols such as +, *, <, and so on that perform operations on operands. Operators can be redefined to perform operations on custom data types. Indexers - these allow an object to be indexed in a manner similar to arrays. Constructors - methods that are called when the object is first created. They are often used to initialize the object's data. Destructors - methods that are called by the runtime execution engine when the object is about to be removed from memory. They are generally used to make sure that any resources which need to be released are handled appropriately. Constants - data members that are known at compile time. Modifiers Each type of modifier may or may not be available to a member. The modifiers may include:

abstract - indicates that a class is intended only to be a base class of other classes.

extern - used to declare a method that is implemented externally (as in a DLL file).

new - hides a member inherited from a base class.

override - required to extend or modify the abstract or virtual implementation of an inherited method, property, indexer, or event.

readonly - fields that are read-only and are initialized at declaration or in a constructor.

sealed - overrides a method in a base class, but itself cannot be overridden further in any derived class.

static – a member that doesn't belong to an instance of the class, but belongs to the class itself.

virtual - used to modify a method, property, indexer or event declaration, and allow it to be overridden in a derived class.

volatile - fields that are modifiable by the environment, a separate thread, or hardware.

Accessibility public - any item in the current assembly or any assembly that references the class, can access this member.

protected - access is limited to the containing class or types derived from the containing class.

internal - any item in the current assembly can access this member.

protected internal - access is limited to the current assembly or types derived from the containing class.

private - access is limited to the containing class.

Page 20: 70-536 test part 1

Members (C# Programming Guide)

Classes and structs have members that represent their data and behavior. A class's members include all the members declared in the class, along with all members (except constructors and destructors) declared in all classes in its inheritance hierarchy. Private members in base classes are inherited but are not accessible from derived classes.

The following table lists the kinds of members a class or struct may contain:

Member Description Fields Fields are variables declared at class scope. A field may be a built-in

numeric type or an instance of another class. For example, a calendar class may have a field that contains the current date.

Constants Constants are fields or properties whose value is set at compile time and cannot be changed.

Properties Properties are methods on a class that are accessed as if they were fields on that class. A property can provide protection for a class field to keep it from being changed without the knowledge of the object.

Methods Methods define the actions that a class can perform. Methods can take parameters that provide input data, and can return output data through parameters. Methods can also return a value directly, without using a parameter.

Events Events provide notifications about occurrences, such as button clicks or the successful completion of a method, to other objects. Events are defined and triggered by using delegates. For more information, see Events and Delegates.

Operators Overloaded operators are considered class members. When you overload an operator, you define it as a public static method in a class. The predefined operators (+, *, <, and so on) are not considered members. For more information, see Overloadable Operators (C# Programming Guide).

Indexers Indexers enable an object to be indexed in a manner similar to arrays. Constructors Constructors are methods that are called when the object is first

created. They are often used to initialize the data of an object. Destructors Destructors are used very rarely in C#. They are methods that are called

by the runtime execution engine when the object is about to be removed from memory. They are generally used to make sure that any resources which must be released are handled appropriately.

Nested Types Nested types are types declared within another type. Nested types are often used to describe objects that are used only by the types that contain them.

abstractThe abstract modifier indicates that the thing being modified has a missing or incomplete implementation. The abstract modifier can be used with classes, methods, properties, indexers, and events. Use the abstract modifier in a class declaration to indicate that a class is intended only to be a base class of other classes. Members marked as abstract, or included in an abstract class, must be implemented by classes that derive from the abstract class.

Page 21: 70-536 test part 1

Exampleabstract class ShapesClass{ abstract public int Area();}class Square : ShapesClass{ int side = 0;

public Square(int n) { side = n; } // Area method is required to avoid // a compile-time error. public override int Area() { return side * side; }

static void Main() { Square sq = new Square(12); Console.WriteLine("Area of the square = {0}", sq.Area()); }

interface I { void M(); } abstract class C : I { public abstract void M(); }

}// Output: Area of the square = 144

Abstract classes have the following features:

An abstract class cannot be instantiated.

An abstract class may contain abstract methods and accessors.

It is not possible to modify an abstract class with the sealed (C# Reference) modifier because the two modifers have opposite meanings. The sealed modifier prevents a class from being inherited and the abstract modifier requires a class to be inherited.

Page 22: 70-536 test part 1

A non-abstract class derived from an abstract class must include actual implementations of all inherited abstract methods and accessors.

Use the abstract modifier in a method or property declaration to indicate that the method or property does not contain implementation.

Abstract methods have the following features:

An abstract method is implicitly a virtual method.

Abstract method declarations are only permitted in abstract classes.

Because an abstract method declaration provides no actual implementation, there is no method body; the method declaration simply ends with a semicolon and there are no curly braces ({ }) following the signature. For example:

public abstract void MyMethod();The implementation is provided by an overriding methodoverride (C# Reference), which is a member of a non-abstract class.

It is an error to use the static or virtual modifiers in an abstract method declaration.

Abstract properties behave like abstract methods, except for the differences in declaration and invocation syntax.

It is an error to use the abstract modifier on a static property.

An abstract inherited property can be overridden in a derived class by including a property declaration that uses the override modifier.

For more information about abstract classes, see Abstract and Sealed Classes and Class Members (C# Programming Guide) and Abstract Class Design.

An abstract class must provide implementation for all interface members.

An abstract class that implements an interface might map the interface methods onto abstract methods. For example:

C# interface I{ void M();}abstract class C : I{ public abstract void M();}

Page 23: 70-536 test part 1

In this example, the class DerivedClass is derived from an abstract class BaseClass. The abstract class contains an abstract method, AbstractMethod, and two abstract properties, X and Y.

abstract class BaseClass // Abstract class{ protected int _x = 100; protected int _y = 150; public abstract void AbstractMethod(); // Abstract method public abstract int X { get; } public abstract int Y { get; }}

class DerivedClass : BaseClass{ public override void AbstractMethod() { _x++; _y++; }

public override int X // overriding property { get { return _x + 10; } }

public override int Y // overriding property { get { return _y + 10; } }

static void Main() { DerivedClass o = new DerivedClass(); o.AbstractMethod(); Console.WriteLine("x = {0}, y = {1}", o.X, o.Y); }}// Output: x = 111, y = 161

In the preceding example, if you attempt to instantiate the abstract class by using a statement like this:

Page 24: 70-536 test part 1

BaseClass bc = new BaseClass(); // Erroryou will get an error saying that the compiler cannot create an instance of the abstract class 'BaseClass'.

extern (C# Reference)

The extern modifier is used to declare a method that is implemented externally. A common use of the extern modifier is with the DllImport attribute when you are using Interop services to call into unmanaged code. In this case, the method must also be declared as static, as shown in the following example:

[DllImport("avifil32.dll")]private static extern void AVIFileInit();

The extern keyword can also define an external assembly alias, which makes it possible to reference different versions of the same component from within a single assembly.

It is an error to use the abstract (C# Reference) and extern modifiers together to modify the same member. Using the extern modifier means that the method is implemented outside the C# code, whereas using the abstract modifier means that the method implementation is not provided in the class.

Example: In this example, the program receives a string from the user and displays it inside a message box. The program uses the MessageBox method imported from the User32.dll library.

//using System.Runtime.InteropServices;class ExternTest{ [DllImport("User32.dll", CharSet=CharSet.Unicode)] public static extern int MessageBox(int h, string m, string c, int type);

static int Main() { string myString; Console.Write("Enter your message: "); myString = Console.ReadLine(); return MessageBox(0, myString, "My Message Box", 0); }

}

This example creates a DLL from a C program that is invoked from within the C# program in the next example.

// cmdll.c// Compile with: /LDint __declspec(dllexport) SampleMethod(int i)

Page 25: 70-536 test part 1

{ return i*10;}This example uses two files, CM.cs and Cmdll.c, to demonstrate extern. The C file is the external DLL created in Example 2 that is invoked from within the C# program.// cm.csusing System;using System.Runtime.InteropServices;public class MainClass { [DllImport("Cmdll.dll")] public static extern int SampleMethod(int x);

static void Main() { Console.WriteLine("SampleMethod() returns {0}.", SampleMethod(5)); }}SampleMethod() returns 50.

RemarksTo build the project:

Compile Cmdll.c to a DLL by using the Visual C++ command line:

cl /LD Cmdll.c

Compile CM.cs using the command line:

csc CM.cs

This will create the executable file CM.exe. When you run this program, SampleMethod will pass the value 5 to the DLL file, which returns the value multiplied by 10.

extern (C# Reference)

The extern modifier is used to declare a method that is implemented externally. A common use of the extern modifier is with the DllImport attribute when you are using Interop services to call into unmanaged code. In this case, the method must also be declared as static, as shown in the following example:

[DllImport("avifil32.dll")]private static extern void AVIFileInit();

Note: The extern keyword can also define an external assembly alias, which makes it possible to reference different versions of the same component from within a single assembly. For more information, see extern alias (C# Reference).

Page 26: 70-536 test part 1

It is an error to use the abstract (C# Reference) and extern modifiers together to modify the same member. Using the extern modifier means that the method is implemented outside the C# code, whereas using the abstract modifier means that the method implementation is not provided in the class.

Note: The extern keyword has more limited uses than in C++. To compare with the C++ keyword, see Using extern to Specify Linkage in the C++ Language Reference.

Example In this example, the program receives a string from the user and displays it inside a message box. The program uses the MessageBox method imported from the User32.dll library.

//using System.Runtime.InteropServices;class ExternTest{ [DllImport("User32.dll", CharSet=CharSet.Unicode)] public static extern int MessageBox(int h, string m, string c, int type);

static int Main() { string myString; Console.Write("Enter your message: "); myString = Console.ReadLine(); return MessageBox(0, myString, "My Message Box", 0); }

}

This example creates a DLL from a C program that is invoked from within the C# program in the next example.

// cmdll.c// Compile with: /LDint __declspec(dllexport) SampleMethod(int i){ return i*10;}This example uses two files, CM.cs and Cmdll.c, to demonstrate extern. The C file is the external DLL created in Example 2 that is invoked from within the C# program.

// cm.csusing System;using System.Runtime.InteropServices;public class MainClass {

Page 27: 70-536 test part 1

[DllImport("Cmdll.dll")] public static extern int SampleMethod(int x);

static void Main() { Console.WriteLine("SampleMethod() returns {0}.", SampleMethod(5)); }}

SampleMethod() returns 50. Remarks To build the project:

Compile Cmdll.c to a DLL by using the Visual C++ command line:

cl /LD Cmdll.c

Compile CM.cs using the command line:

csc CM.cs

This will create the executable file CM.exe. When you run this program, SampleMethod will pass the value 5 to the DLL file, which returns the value multiplied by 10.

new Modifier (C# Reference)

When used as a modifier, the new keyword explicitly hides a member inherited from a base class. When you hide an inherited member, the derived version of the member replaces the base-class version. Although you can hide members without the use of the new modifier, the result is a warning. If you use new to explicitly hide a member, it suppresses this warning and documents the fact that the derived version is intended as a replacement.

To hide an inherited member, declare it in the derived class by using the same name, and modify it with the new modifier. For example:

public class BaseC{ public int x; public void Invoke() { }}public class DerivedC : BaseC{ new public void Invoke() { }}

In this example, BaseC.Invoke is hidden by DerivedC.Invoke. The field x is not affected because it is not hidden by a similar name.

Page 28: 70-536 test part 1

Name hiding through inheritance takes one of the following forms:

A constant, field, property, or type introduced in a class or struct hides all base class members with the same name.

A method introduced in a class or struct hides properties, fields, and types, with the same name, in the base class. It also hides all base class methods with the same signature.

An indexer introduced in a class or struct hides all base class indexers with the same signature.

It is an error to use both new and override on the same member because the two modifiers have mutually exclusive meanings. The new modifier creates a new member with the same name and causes the original member to become hidden. The override modifier extends the implementation for an inherited member.

Using the new modifier in a declaration that does not hide an inherited member generates a warning.

Example In this example, a base class, BaseC, and a derived class, DerivedC, use the same field name x, which hides the value of the inherited field. The example demonstrates the use of the new modifier. It also demonstrates how to access the hidden members of the base class by using their fully qualified names.

public class BaseC{ public static int x = 55; public static int y = 22;}

public class DerivedC : BaseC{ // Hide field 'x'. new public static int x = 100;

static void Main() { // Display the new value of x: Console.WriteLine(x);

// Display the hidden value of x: Console.WriteLine(BaseC.x);

// Display the unhidden member y: Console.WriteLine(y); }}

Page 29: 70-536 test part 1

/*Output:1005522*/

In this example, a nested class hides a class that has the same name in the base class. The example demonstrates how to use the new modifier to eliminate the warning message and how to access the hidden class members by using their fully qualified names.

public class BaseC { public class NestedC { public int x = 200; public int y; }}

public class DerivedC : BaseC { // Nested type hiding the base type members. new public class NestedC { public int x = 100; public int y; public int z; }

static void Main() { // Creating an object from the overlapping class: NestedC c1 = new NestedC();

// Creating an object from the hidden class: BaseC.NestedC c2 = new BaseC.NestedC();

Console.WriteLine(c1.x); Console.WriteLine(c2.x); }}/*Output:100200*/

Page 30: 70-536 test part 1

If you remove the new modifier, the program will still compile and run, but you will get the following warning:

Copy CodeThe keyword new is required on 'MyDerivedC.x' because it hides inherited member 'MyBaseC.x'.You can also use the new modifier to modify a nested type if the nested type is hiding another type, as demonstrated in the following example.

new Modifier (C# Reference)

When used as a modifier, the new keyword explicitly hides a member inherited from a base class. When you hide an inherited member, the derived version of the member replaces the base-class version. Although you can hide members without the use of the new modifier, the result is a warning. If you use new to explicitly hide a member, it suppresses this warning and documents the fact that the derived version is intended as a replacement.

To hide an inherited member, declare it in the derived class by using the same name, and modify it with the new modifier. For example:

public class BaseC{ public int x; public void Invoke() { }}public class DerivedC : BaseC{ new public void Invoke() { }}

In this example, BaseC.Invoke is hidden by DerivedC.Invoke. The field x is not affected because it is not hidden by a similar name.

Name hiding through inheritance takes one of the following forms:

A constant, field, property, or type introduced in a class or struct hides all base class members with the same name.

A method introduced in a class or struct hides properties, fields, and types, with the same name, in the base class. It also hides all base class methods with the same signature.

An indexer introduced in a class or struct hides all base class indexers with the same signature.

Page 31: 70-536 test part 1

It is an error to use both new and override on the same member because the two modifiers have mutually exclusive meanings. The new modifier creates a new member with the same name and causes the original member to become hidden. The override modifier extends the implementation for an inherited member.

Using the new modifier in a declaration that does not hide an inherited member generates a warning.

Example In this example, a base class, BaseC, and a derived class, DerivedC, use the same field name x, which hides the value of the inherited field. The example demonstrates the use of the new modifier. It also demonstrates how to access the hidden members of the base class by using their fully qualified names.

public class BaseC{ public static int x = 55; public static int y = 22;}

public class DerivedC : BaseC{ // Hide field 'x'. new public static int x = 100;

static void Main() { // Display the new value of x: Console.WriteLine(x);

// Display the hidden value of x: Console.WriteLine(BaseC.x);

// Display the unhidden member y: Console.WriteLine(y); }}/*Output:1005522*/

In this example, a nested class hides a class that has the same name in the base class. The example demonstrates how to use the new modifier to eliminate the warning message and how to access the hidden class members by using their fully qualified names.

Page 32: 70-536 test part 1

public class BaseC { public class NestedC { public int x = 200; public int y; }}

public class DerivedC : BaseC { // Nested type hiding the base type members. new public class NestedC { public int x = 100; public int y; public int z; }

static void Main() { // Creating an object from the overlapping class: NestedC c1 = new NestedC();

// Creating an object from the hidden class: BaseC.NestedC c2 = new BaseC.NestedC();

Console.WriteLine(c1.x); Console.WriteLine(c2.x); }}/*Output:100200*/

If you remove the new modifier, the program will still compile and run, but you will get the following warning:

The keyword new is required on 'MyDerivedC.x' because it hides inherited member 'MyBaseC.x'.You can also use the new modifier to modify a nested type if the nested type is hiding another type, as demonstrated in the following example

override (C# Reference)

Page 33: 70-536 test part 1

The override modifier is required to extend or modify the abstract or virtual implementation of an inherited method, property, indexer, or event.

Example In this example, the Square class must provide an overridden implementation of Area because Area is inherited from the abstract ShapesClass:

abstract class ShapesClass{ abstract public int Area();}class Square : ShapesClass{ int side = 0;

public Square(int n) { side = n; } // Area method is required to avoid // a compile-time error. public override int Area() { return side * side; }

static void Main() { Square sq = new Square(12); Console.WriteLine("Area of the square = {0}", sq.Area()); }

interface I { void M(); } abstract class C : I { public abstract void M(); }

}// Output: Area of the square = 144

An override method provides a new implementation of a member that is inherited from a base class. The method that is overridden by an override declaration is known as the overridden base method. The overridden base method must have the same signature as

Page 34: 70-536 test part 1

the override method. For information about inheritance, see Inheritance (C# Programming Guide).

You cannot override a non-virtual or static method. The overridden base method must be virtual, abstract, or override.

An override declaration cannot change the accessibility of the virtual method. Both the override method and the virtual method must have the same access level modifier.

You cannot use the new, static, virtual, or abstract modifiers to modify an override method.

An overriding property declaration must specify exactly the same access modifier, type, and name as the inherited property, and the overridden property must be virtual, abstract, or override.

For more information about how to use the override keyword, see Versioning with the Override and New Keywords (C# Programming Guide) and Knowing when to use Override and New Keywords.

This example defines a base class named Employee, and a derived class named SalesEmployee. The SalesEmployee class includes an extra property, salesbonus, and overrides the method CalculatePay in order to take it into account.

class TestOverride{ public class Employee { public string name;

// Basepay is defined as protected, so that it may be // accessed only by this class and derrived classes. protected decimal basepay;

// Constructor to set the name and basepay values. public Employee(string name, decimal basepay) { this.name = name; this.basepay = basepay; }

// Declared virtual so it can be overridden. public virtual decimal CalculatePay() { return basepay; } }

// Derive a new class from Employee.

Page 35: 70-536 test part 1

public class SalesEmployee : Employee { // New field that will affect the base pay. private decimal salesbonus;

// The constructor calls the base-class version, and // initializes the salesbonus field. public SalesEmployee(string name, decimal basepay, decimal salesbonus) : base(name, basepay) { this.salesbonus = salesbonus; }

// Override the CalculatePay method // to take bonus into account. public override decimal CalculatePay() { return basepay + salesbonus; } }

static void Main() { // Create some new employees. SalesEmployee employee1 = new SalesEmployee("Alice", 1000, 500); Employee employee2 = new Employee("Bob", 1200);

Console.WriteLine("Employee4 " + employee1.name + " earned: " + employee1.CalculatePay()); Console.WriteLine("Employee4 " + employee2.name + " earned: " + employee2.CalculatePay()); }}/* Output: Employee4 Alice earned: 1500 Employee4 Bob earned: 1200*/

readonly (C# Reference)

The readonly keyword is a modifier that you can use on fields. When a field declaration includes a readonly modifier, assignments to the fields introduced by the declaration can only occur as part of the declaration or in a constructor in the same class.

Example

Page 36: 70-536 test part 1

In this example, the value of the field year cannot be changed in the method ChangeYear, even though it is assigned a value in the class constructor:

class Age{ readonly int _year; Age(int year) { _year = year; } void ChangeYear() { //_year = 1967; // Compile error if uncommented. }}

You can assign a value to a readonly field only in the following contexts:

When the variable is initialized in the declaration, for example:

public readonly int y = 5;For an instance field, in the instance constructors of the class that contains the field declaration, or for a static field, in the static constructor of the class that contains the field declaration. These are also the only contexts in which it is valid to pass a readonly field as an out or ref parameter.

Note: The readonly keyword is different from the const keyword. A const field can only be initialized at the declaration of the field. A readonly field can be initialized either at the declaration or in a constructor. Therefore, readonly fields can have different values depending on the constructor used. Also, while a const field is a compile-time constant, the readonly field can be used for runtime constants as in the following example: public static readonly uint timeStamp = (uint)DateTime.Now.Ticks;

public class ReadOnlyTest{ class SampleClass { public int x; // Initialize a readonly field public readonly int y = 25; public readonly int z;

public SampleClass() { // Initialize a readonly instance field z = 24; }

Page 37: 70-536 test part 1

public SampleClass(int p1, int p2, int p3) { x = p1; y = p2; z = p3; } }

static void Main() { SampleClass p1 = new SampleClass(11, 21, 32); // OK Console.WriteLine("p1: x={0}, y={1}, z={2}", p1.x, p1.y, p1.z); SampleClass p2 = new SampleClass(); p2.x = 55; // OK Console.WriteLine("p2: x={0}, y={1}, z={2}", p2.x, p2.y, p2.z); }}/* Output: p1: x=11, y=21, z=32 p2: x=55, y=25, z=24*/

In the preceding example, if you use a statement like this:

p2.y = 66; // Error

you will get the compiler error message:

The left-hand side of an assignment must be an l-value

Which is the same error you get when you attempt to assign a value to a constant?

sealedWhen applied to a class, the sealed modifier prevents other classes from inheriting from it. In the following example, class B inherits from class A, but no class can inherit from class B.

class A {} sealed class B : A {}You can also use the sealed modifier on a method or property that overrides a virtual method or property in a base class. This enables you to allow classes to derive from your class and prevent them from overriding specific virtual methods or properties.

Example

Page 38: 70-536 test part 1

In the following example, Z inherits from Y but Z cannot override the virtual function F that is declared in X and sealed in Y.

class X{ protected virtual void F() { Console.WriteLine("X.F"); } protected virtual void F2() { Console.WriteLine("X.F2"); }}class Y : X{ sealed protected override void F() { Console.WriteLine("Y.F"); } protected override void F2() { Console.WriteLine("X.F3"); }}class Z : Y{ // Attempting to override F causes compiler error CS0239. // protected override void F() { Console.WriteLine("C.F"); }

// Overriding F2 is allowed. protected override void F2() { Console.WriteLine("Z.F2"); }}

When you define new methods or properties in a class, you can prevent deriving classes from overriding them by not declaring them as virtual.

It is an error to use the abstract modifier with a sealed class, because an abstract class must be inherited by a class that provides an implementation of the abstract methods or properties.

When applied to a method or property, the sealed modifier must always be used with override.

Because structs are implicitly sealed, they cannot be inherited.

For more information, see Inheritance (C# Programming Guide).

sealed class SealedClass{ public int x; public int y;}

class SealedTest2{ static void Main() { SealedClass sc = new SealedClass(); sc.x = 110; sc.y = 150;

Page 39: 70-536 test part 1

Console.WriteLine("x = {0}, y = {1}", sc.x, sc.y); }}// Output: x = 110, y = 150

In the previous example, you might try to inherit from the sealed class by using the following statement:

class MyDerivedC: SealedClass {} // Error

The result is an error message:

'MyDerivedC' cannot inherit from sealed class 'SealedClass'.

static (C# Reference)

The static modifier can be used with classes, fields, methods, properties, operators, events, and constructors, but it cannot be used with indexers, destructors, or types other than classes. The static modifier on a class means that the class cannot be instantiated, and that all of its members are static. A static member has one version regardless of how many instances of its enclosing type are created. For more information, see Static Classes and Static Class Members (C# Programming Guide).

Example The following class is declared as static and contains only static methods:

static class CompanyEmployee{ public static void DoSomething() { /*...*/ } public static void DoSomethingElse() { /*...*/ }}

A constant or type declaration is implicitly a static member.

A static member cannot be referenced through an instance. Instead, it is referenced through the type name. For example, consider the following class:

public class MyBaseC{ public struct MyStruct { public static int x = 100; }}

To refer to the static member x, use the fully qualified name (unless it is accessible from the same scope):

Page 40: 70-536 test part 1

MyBaseC.MyStruct.xWhile an instance of a class contains a separate copy of all instance fields of the class, there is only one copy of each static field.

It is not possible to use this to reference static methods or property accessors.

If the static keyword is applied to a class, all the members of the class must be static.

Classes and static classes may have static constructors. Static constructors are called at some point between when the program starts and the class is instantiated.

Note: The static keyword has more limited uses than in C++. To compare with the C++ keyword, see Static (C++). To demonstrate static members, consider a class that represents a company employee. Assume that the class contains a method to count employees and a field to store the number of employees. Both the method and the field do not belong to any instance employee. Instead they belong to the company class. Therefore, they should be declared as static members of the class.

This example reads the name and ID of a new employee, increments the employee counter by one, and displays the information for the new employee and the new number of employees. For simplicity, this program reads the current number of employees from the keyboard. In a real application, this information should be read from a file.

public class Employee4{ public string id; public string name;

public Employee4() { }

public Employee4(string name, string id) { this.name = name; this.id = id; }

public static int employeeCounter;

public static int AddEmployee() { return ++employeeCounter; }}

Page 41: 70-536 test part 1

class MainClass : Employee4{ static void Main() { Console.Write("Enter the employee's name: "); string name = Console.ReadLine(); Console.Write("Enter the employee's ID: "); string id = Console.ReadLine();

// Create and configure the employee object: Employee4 e = new Employee4(name, id); Console.Write("Enter the current number of employees: "); string n = Console.ReadLine(); Employee4.employeeCounter = Int32.Parse(n); Employee4.AddEmployee();

// Display the new information: Console.WriteLine("Name: {0}", e.name); Console.WriteLine("ID: {0}", e.id); Console.WriteLine("New Number of Employees: {0}", Employee4.employeeCounter); }} /* Input: Matthias Berndt AF643G 15 * Sample Output: Enter the employee's name: Matthias Berndt Enter the employee's ID: AF643G Enter the current number of employees: 15 Name: Matthias Berndt ID: AF643G New Number of Employees: 16 */

This example shows that although you can initialize a static field by using another static field not yet declared, the results will be undefined until you explicitly assign a value to the static field.

class Test{ static int x = y; static int y = 5;

static void Main()

Page 42: 70-536 test part 1

{ Console.WriteLine(Test.x); Console.WriteLine(Test.y);

Test.x = 99; Console.WriteLine(Test.x); }}/*Output: 0 5 99*/

virtual (C# Reference)

The virtual keyword is used to modify a method, property, indexer, or event declaration and allow for it to be overridden in a derived class. For example, this method can be overridden by any class that inherits it:

public virtual double Area() { return x * y;}The implementation of a virtual member can be changed by an overriding member in a derived class. For more information about how to use the virtual keyword, see Versioning with the Override and New Keywords (C# Programming Guide) and Knowing When to Use Override and New Keywords (C# Programming Guide).

Remarks When a virtual method is invoked, the run-time type of the object is checked for an overriding member. The overriding member in the most derived class is called, which might be the original member, if no derived class has overridden the member.

By default, methods are non-virtual. You cannot override a non-virtual method.

You cannot use the virtual modifier with the static, abstract, private, or override modifiers. The following example shows a virtual property:

class MyBaseClass{ // virtual auto-implemented property. Overrides can only // provide specialized behavior if they implement get and set accessors. public virtual string Name { get; set; }

// ordinary virtual property with backing field private int num; public virtual int Number

Page 43: 70-536 test part 1

{ get { return num; } set { num = value; } }}

class MyDerivedClass : MyBaseClass{ private string name;

// Override auto-implemented property with ordinary property // to provide specialized accessor behavior. public override string Name { get { return name; } set { if (value != String.Empty) { name = value; } else { name = "Unknown"; } } }

}

Virtual properties behave like abstract methods, except for the differences in declaration and invocation syntax.

It is an error to use the virtual modifier on a static property.

A virtual inherited property can be overridden in a derived class by including a property declaration that uses the override modifier.

Example In this example, the Dimensions class contains the two coordinates x, y, and the Area() virtual method. Different shape classes such as Circle, Cylinder, and Sphere inherit the Dimensions class, and the surface area is calculated for each figure. Each derived class has it own override implementation of Area(). The program calculates and displays the

Page 44: 70-536 test part 1

appropriate area for each figure by invoking the appropriate implementation of Area() according to the object associated with the method.

Notice that the inherited classes Circle, Sphere, and Cylinder are all using constructors that initialize the base class, for example:

public Cylinder(double r, double h): base(r, h) {}This is similar to the C++ initialization list.

class TestClass{ public class Dimensions { public const double PI = Math.PI; protected double x, y; public Dimensions() { } public Dimensions(double x, double y) { this.x = x; this.y = y; }

public virtual double Area() { return x * y; } }

public class Circle : Dimensions { public Circle(double r) : base(r, 0) { }

public override double Area() { return PI * x * x; } }

class Sphere : Dimensions { public Sphere(double r) : base(r, 0) { }

public override double Area()

Page 45: 70-536 test part 1

{ return 4 * PI * x * x; } }

class Cylinder : Dimensions { public Cylinder(double r, double h) : base(r, h) { }

public override double Area() { return 2 * PI * x * x + 2 * PI * x * y; } }

static void Main() { double r = 3.0, h = 5.0; Dimensions c = new Circle(r); Dimensions s = new Sphere(r); Dimensions l = new Cylinder(r, h); // Display results: Console.WriteLine("Area of Circle = {0:F2}", c.Area()); Console.WriteLine("Area of Sphere = {0:F2}", s.Area()); Console.WriteLine("Area of Cylinder = {0:F2}", l.Area()); } } /* Output: Area of Circle = 28.27 Area of Sphere = 113.10 Area of Cylinder = 150.80 */volatile (C# Reference)

The volatile keyword indicates that a field might be modified by multiple threads that are executing at the same time. Fields that are declared volatile are not subject to compiler optimizations that assume access by a single thread. This ensures that the most up-to-date value is present in the field at all times.

The volatile modifier is usually used for a field that is accessed by multiple threads without using the lock statement to serialize access. See How to: Create and Terminate Threads (C# Programming Guide) for an example of volatile in a multi-threaded scenario.

The volatile keyword can be applied to fields of these types:

Reference types.

Page 46: 70-536 test part 1

Pointer types (in an unsafe context). Note that although the pointer itself can be volatile, the object that it points to cannot. In other words, you cannot declare a "pointer to volatile."

Integral types such as sbyte, byte, short, ushort, int, uint, char, float, and bool.

An enum type with an integral base type.

Generic type parameters known to be reference types.

IntPtr and UIntPtr.

The volatile keyword can only be applied to fields of a class or struct. Local variables cannot be declared volatile.

Example The following example shows how to declare a public field variable as volatile.

class VolatileTest{ public volatile int i;

public void Test(int _i) { i = _i; }}

Collection interfacesAs the name implies, a collection interface is an interface that provides the contract for a specific collection.

The .NET Framework provides a number of standard collection interfaces:

ICollection - Implemented by all collections IList - Used by collections that can be indexed IDictionary - For key/value-based collections such as Hashtable and SortedList IComparer - Allows custom comparison for purpose of sorting and ordering IEqualityComparer - Allows custom equality comparisons for collections that depend on equality but not order (like Hashtable) IKeyComparer - Replaced by IEqualityComparer since .NET 2.0 beta 2 IHashCodeProvider - Replaced by IEqualityComparer since .NET 2.0 beta 2 IEnumerable - Provides the Enumerator for a collection IEnumerator - Iterates over a collection and supports the foreach loop IDictionaryEnumerator - An enumerator that enumerates a dictionary and add support for accessing the key and value of the current item.

Page 47: 70-536 test part 1

Contents 1 ICollection 2 IList 3 IDictionary 4 IComparer 5 IEqualityComparer 6 IKeyComparer 7 IHashCodeProvider 8 IEnumerable 9 IEnumerator 10 IDictionaryEnumerator

ICollectionICollection extends IEnumerable. It provides size and synchronization members in addition to enumeration.

IListIList extends ICollection. It allows access to the items of a collection by their index.

IDictionaryIDictionary extends ICollection. It allows access to the items of a collection by their key.

IComparerAllows custom comparison for the purposes of sorting and ordering.

IEqualityComparerAllows custom equality comparisons for collections that depend on equality but not order (like Hashtable)

IKeyComparerReplaced by IEqualityComparer since .NET 2.0 beta 2

IHashCodeProviderReplaced by IEqualityComparer since .NET 2.0 beta 2

IEnumerableIEnumerable allows a class to be enumerated using an enumerator. A class should inherit from IEnumerable in order to provide an enumerator through the GetEnumerator() method.

The foreach automatically calls GetEnumerator at the beginning of the loop and then uses that enumerator to go through the loop.

IEnumeratorAn IEnumerator iterates over each item in a collection. It allows access to the current item and the ability to proceed to the next item. The foreach loop uses an enumerator to go through each item.

IDictionaryEnumerator

Page 48: 70-536 test part 1

A IDictionaryEnumerator extends IEnumerator. It also adds support for accessing the key and value of the current item.

CollectionBase Class

Provides the abstract base class for a strongly typed collection.

Namespace: System.CollectionsAssembly: mscorlib (in mscorlib.dll)

[SerializableAttribute][ComVisibleAttribute(true)]public abstract class CollectionBase : IList, ICollection, IEnumerable

Remarks A CollectionBase instance is always modifiable. See ReadOnlyCollectionBase for a read-only version of this class. The capacity of a CollectionBase is the number of elements the CollectionBase can hold. As elements are added to a CollectionBase, the capacity is automatically increased as required through reallocation. The capacity can be decreased by setting the Capacity property explicitly.

Notes to Implementers: This base class is provided to make it easier for implementers to create a strongly typed custom collection. Implementers are encouraged to extend this base class instead of creating their own.

Examples The following code example implements the CollectionBase class and uses that implementation to create a collection of Int16 objects.

using System;using System.Collections;

public class Int16Collection : CollectionBase {

public Int16 this[ int index ] { get { return( (Int16) List[index] ); } set { List[index] = value; } }

public int Add( Int16 value ) { return( List.Add( value ) ); }

Page 49: 70-536 test part 1

public int IndexOf( Int16 value ) { return( List.IndexOf( value ) ); }

public void Insert( int index, Int16 value ) { List.Insert( index, value ); }

public void Remove( Int16 value ) { List.Remove( value ); }

public bool Contains( Int16 value ) { // If value is not of type Int16, this will return false. return( List.Contains( value ) ); }

protected override void OnInsert( int index, Object value ) { // Insert additional code to be run only when inserting values. }

protected override void OnRemove( int index, Object value ) { // Insert additional code to be run only when removing values. }

protected override void OnSet( int index, Object oldValue, Object newValue ) { // Insert additional code to be run only when setting values. }

protected override void OnValidate( Object value ) { if ( value.GetType() != typeof(System.Int16) ) throw new ArgumentException( "value must be of type Int16.", "value" ); }

}

public class SamplesCollectionBase {

public static void Main() {

// Create and initialize a new CollectionBase. Int16Collection myI16 = new Int16Collection();

// Add elements to the collection. myI16.Add( (Int16) 1 ); myI16.Add( (Int16) 2 ); myI16.Add( (Int16) 3 ); myI16.Add( (Int16) 5 );

Page 50: 70-536 test part 1

myI16.Add( (Int16) 7 );

// Display the contents of the collection using foreach. This is the preferred method. Console.WriteLine( "Contents of the collection (using foreach):" ); PrintValues1( myI16 );

// Display the contents of the collection using the enumerator. Console.WriteLine( "Contents of the collection (using enumerator):" ); PrintValues2( myI16 );

// Display the contents of the collection using the Count property and the Item property. Console.WriteLine( "Initial contents of the collection (using Count and Item):" ); PrintIndexAndValues( myI16 );

// Search the collection with Contains and IndexOf. Console.WriteLine( "Contains 3: {0}", myI16.Contains( 3 ) ); Console.WriteLine( "2 is at index {0}.", myI16.IndexOf( 2 ) ); Console.WriteLine();

// Insert an element into the collection at index 3. myI16.Insert( 3, (Int16) 13 ); Console.WriteLine( "Contents of the collection after inserting at index 3:" ); PrintIndexAndValues( myI16 );

// Get and set an element using the index. myI16[4] = 123; Console.WriteLine( "Contents of the collection after setting the element at index 4 to 123:" ); PrintIndexAndValues( myI16 );

// Remove an element from the collection. myI16.Remove( (Int16) 2 );

// Display the contents of the collection using the Count property and the Item property. Console.WriteLine( "Contents of the collection after removing the element 2:" ); PrintIndexAndValues( myI16 );

}

// Uses the Count property and the Item property. public static void PrintIndexAndValues( Int16Collection myCol ) { for ( int i = 0; i < myCol.Count; i++ ) Console.WriteLine( " [{0}]: {1}", i, myCol[i] ); Console.WriteLine(); }

// Uses the foreach statement which hides the complexity of the enumerator.

Page 51: 70-536 test part 1

// NOTE: The foreach statement is the preferred way of enumerating the contents of a collection. public static void PrintValues1( Int16Collection myCol ) { foreach ( Int16 i16 in myCol ) Console.WriteLine( " {0}", i16 ); Console.WriteLine(); }

// Uses the enumerator. // NOTE: The foreach statement is the preferred way of enumerating the contents of a collection. public static void PrintValues2( Int16Collection myCol ) { System.Collections.IEnumerator myEnumerator = myCol.GetEnumerator(); while ( myEnumerator.MoveNext() ) Console.WriteLine( " {0}", myEnumerator.Current ); Console.WriteLine(); }}

/* This code produces the following output.

Contents of the collection (using foreach): 1 2 3 5 7

Contents of the collection (using enumerator): 1 2 3 5 7

Initial contents of the collection (using Count and Item): [0]: 1 [1]: 2 [2]: 3 [3]: 5 [4]: 7

Contains 3: True2 is at index 1.

Contents of the collection after inserting at index 3: [0]: 1

Page 52: 70-536 test part 1

[1]: 2 [2]: 3 [3]: 13 [4]: 5 [5]: 7

Contents of the collection after setting the element at index 4 to 123: [0]: 1 [1]: 2 [2]: 3 [3]: 13 [4]: 123 [5]: 7

Contents of the collection after removing the element 2: [0]: 1 [1]: 3 [2]: 13 [3]: 123 [4]: 7

*/

ReadOnlyCollectionBase Class

Provides the abstract base class for a strongly typed non-generic read-only collection.

Namespace: System.CollectionsAssembly: mscorlib (in mscorlib.dll)

C#[SerializableAttribute][ComVisibleAttribute(true)]public abstract class ReadOnlyCollectionBase : ICollection, IEnumerable

Remarks A ReadOnlyCollectionBase instance is always read-only. See CollectionBase for a modifiable version of this class.

Notes to Implementers: This base class is provided to make it easier for implementers to create a strongly typed read-only custom collection. Implementers are encouraged to extend this base class instead of creating their own. Members of this base class are protected and are intended to be used through a derived class only. This class makes the underlying collection available through the InnerList property, which is intended for use only by classes that are derived directly from ReadOnlyCollectionBase. The derived class must ensure that its own users cannot modify the underlying collection.

Page 53: 70-536 test part 1

Examples The following code example implements the ReadOnlyCollectionBase class.

using System;using System.Collections;

public class ROCollection : ReadOnlyCollectionBase {

public ROCollection( IList sourceList ) { InnerList.AddRange( sourceList ); }

public Object this[ int index ] { get { return( InnerList[index] ); } }

public int IndexOf( Object value ) { return( InnerList.IndexOf( value ) ); }

public bool Contains( Object value ) { return( InnerList.Contains( value ) ); }

}

public class SamplesCollectionBase {

public static void Main() {

// Create an ArrayList. ArrayList myAL = new ArrayList(); myAL.Add( "red" ); myAL.Add( "blue" ); myAL.Add( "yellow" ); myAL.Add( "green" ); myAL.Add( "orange" ); myAL.Add( "purple" );

// Create a new ROCollection that contains the elements in myAL. ROCollection myCol = new ROCollection( myAL );

// Display the contents of the collection using foreach. This is the preferred method. Console.WriteLine( "Contents of the collection (using foreach):" ); PrintValues1( myCol );

Page 54: 70-536 test part 1

// Display the contents of the collection using the enumerator. Console.WriteLine( "Contents of the collection (using enumerator):" ); PrintValues2( myCol );

// Display the contents of the collection using the Count property and the Item property. Console.WriteLine( "Contents of the collection (using Count and Item):" ); PrintIndexAndValues( myCol );

// Search the collection with Contains and IndexOf. Console.WriteLine( "Contains yellow: {0}", myCol.Contains( "yellow" ) ); Console.WriteLine( "orange is at index {0}.", myCol.IndexOf( "orange" ) ); Console.WriteLine();

}

// Uses the Count property and the Item property. public static void PrintIndexAndValues( ROCollection myCol ) { for ( int i = 0; i < myCol.Count; i++ ) Console.WriteLine( " [{0}]: {1}", i, myCol[i] ); Console.WriteLine(); }

// Uses the foreach statement which hides the complexity of the enumerator. // NOTE: The foreach statement is the preferred way of enumerating the contents of a collection. public static void PrintValues1( ROCollection myCol ) { foreach ( Object obj in myCol ) Console.WriteLine( " {0}", obj ); Console.WriteLine(); }

// Uses the enumerator. // NOTE: The foreach statement is the preferred way of enumerating the contents of a collection. public static void PrintValues2( ROCollection myCol ) { System.Collections.IEnumerator myEnumerator = myCol.GetEnumerator(); while ( myEnumerator.MoveNext() ) Console.WriteLine( " {0}", myEnumerator.Current ); Console.WriteLine(); }

}

/* This code produces the following output.

Page 55: 70-536 test part 1

Contents of the collection (using foreach): red blue yellow green orange purple

Contents of the collection (using enumerator): red blue yellow green orange purple

Contents of the collection (using Count and Item): [0]: red [1]: blue [2]: yellow [3]: green [4]: orange [5]: purple

Contains yellow: Trueorange is at index 4.

*/

Comparer class

You must implement the IComparer interface if you want to provide a custom comparison method in your code:

class MyCustomComparer : IComparer{CaseInsensitiveComparer _comparer = new CaseInsensitiveComparer(); public int Compare(object x, object y){// custom comparison herereturn _comparer.Compare(x, y);}}The Compare method should return -1, 0 or 1 (less than zero, zero, more than zero) to indicate that object x is less than y, equals to y or more than y, respectively.

Page 56: 70-536 test part 1

Then you can use it as parameter invoking the Sort method for any collection you have: myList.Sort(new MyCustomComparer());

IComparer Interface

Exposes a method that compares two objects.

Namespace: System.CollectionsAssembly: mscorlib (in mscorlib.dll)Syntax

Visual Basic (Declaration)<ComVisibleAttribute(True)> _Public Interface IComparerVisual Basic (Usage)Dim instance As IComparer

C#[ComVisibleAttribute(true)]public interface IComparer

Remarks This interface is used in conjunction with the Array..::.Sort and Array..::.BinarySearch methods. It provides a way to customize the sort order of a collection.

The default implementation of this interface is the Comparer class. For the generic version of this interface, see System.Collections.Generic..::.IComparer<(Of <(T>)>).

Examples The following code example demonstrates the use of the IComparer interface to sort an ArrayList object. In this example, the IComparer interface is implemented using the CaseInsensitiveComparer class to reverse the order of the contents of the ArrayList.

Visual Basic Imports SystemImports System.CollectionsImports Microsoft.VisualBasic

Public Class SamplesArrayList

Public Class myReverserClass Implements IComparer

' Calls CaseInsensitiveComparer.Compare with the parameters reversed. Public Function Compare( ByVal x As Object, ByVal y As Object) As Integer _ Implements IComparer.Compare Return New CaseInsensitiveComparer().Compare(y, x) End Function 'IComparer.Compare

Page 57: 70-536 test part 1

End Class 'myReverserClass

Public Shared Sub Main()

' Creates and initializes a new ArrayList. Dim myAL As New ArrayList() myAL.Add("The") myAL.Add("quick") myAL.Add("brown") myAL.Add("fox") myAL.Add("jumps") myAL.Add("over") myAL.Add("the") myAL.Add("lazy") myAL.Add("dog")

' Displays the values of the ArrayList. Console.WriteLine("The ArrayList initially contains the following values:") PrintIndexAndValues(myAL)

' Sorts the values of the ArrayList using the default comparer. myAL.Sort() Console.WriteLine("After sorting with the default comparer:") PrintIndexAndValues(myAL)

' Sorts the values of the ArrayList using the reverse case-insensitive comparer. Dim myComparer = New myReverserClass() myAL.Sort(myComparer) Console.WriteLine("After sorting with the reverse case-insensitive comparer:") PrintIndexAndValues(myAL)

End Sub 'Main

Public Shared Sub PrintIndexAndValues(myList As IEnumerable) Dim i As Integer = 0 Dim obj As [Object] For Each obj In myList Console.WriteLine(vbTab + "[{0}]:" + vbTab + "{1}", i, obj) i = i + 1 Next obj Console.WriteLine() End Sub 'PrintIndexAndValues

End Class 'SamplesArrayList

'This code produces the following output.'The ArrayList initially contains the following values:

Page 58: 70-536 test part 1

' [0]: The' [1]: quick' [2]: brown' [3]: fox' [4]: jumps' [5]: over' [6]: the' [7]: lazy' [8]: dog''After sorting with the default comparer:' [0]: brown' [1]: dog' [2]: fox' [3]: jumps' [4]: lazy' [5]: over' [6]: quick' [7]: the' [8]: The''After sorting with the reverse case-insensitive comparer:' [0]: the' [1]: The' [2]: quick' [3]: over' [4]: lazy' [5]: jumps' [6]: fox' [7]: dog' [8]: brown

C# using System;using System.Collections;

public class SamplesArrayList {

public class myReverserClass : IComparer {

// Calls CaseInsensitiveComparer.Compare with the parameters reversed. int IComparer.Compare( Object x, Object y ) { return( (new CaseInsensitiveComparer()).Compare( y, x ) ); }

}

public static void Main() {

Page 59: 70-536 test part 1

// Creates and initializes a new ArrayList. ArrayList myAL = new ArrayList(); myAL.Add( "The" ); myAL.Add( "quick" ); myAL.Add( "brown" ); myAL.Add( "fox" ); myAL.Add( "jumps" ); myAL.Add( "over" ); myAL.Add( "the" ); myAL.Add( "lazy" ); myAL.Add( "dog" );

// Displays the values of the ArrayList. Console.WriteLine( "The ArrayList initially contains the following values:" ); PrintIndexAndValues( myAL );

// Sorts the values of the ArrayList using the default comparer. myAL.Sort(); Console.WriteLine( "After sorting with the default comparer:" ); PrintIndexAndValues( myAL );

// Sorts the values of the ArrayList using the reverse case-insensitive comparer. IComparer myComparer = new myReverserClass(); myAL.Sort( myComparer ); Console.WriteLine( "After sorting with the reverse case-insensitive comparer:" ); PrintIndexAndValues( myAL );

}

public static void PrintIndexAndValues( IEnumerable myList ) { int i = 0; foreach ( Object obj in myList ) Console.WriteLine( "\t[{0}]:\t{1}", i++, obj ); Console.WriteLine(); }

}

/* This code produces the following output.The ArrayList initially contains the following values: [0]: The [1]: quick [2]: brown [3]: fox [4]: jumps [5]: over [6]: the

Page 60: 70-536 test part 1

[7]: lazy [8]: dog

After sorting with the default comparer: [0]: brown [1]: dog [2]: fox [3]: jumps [4]: lazy [5]: over [6]: quick [7]: the [8]: The

After sorting with the reverse case-insensitive comparer: [0]: the [1]: The [2]: quick [3]: over [4]: lazy [5]: jumps [6]: fox [7]: dog [8]: brown */

Remarks This interface is used in conjunction with the Array..::.Sort and Array..::.BinarySearch methods. It provides a way to customize the sort order of a collection.

The default implementation of this interface is the Comparer class. For the generic version of this interface, see System.Collections.Generic..::.IComparer<(Of <(T>)>).

Examples The following code example demonstrates the use of the IComparer interface to sort an ArrayList object. In this example, the IComparer interface is implemented using the CaseInsensitiveComparer class to reverse the order of the contents of the ArrayList.

Visual Basic Imports SystemImports System.CollectionsImports Microsoft.VisualBasic

Public Class SamplesArrayList

Public Class myReverserClass Implements IComparer

Page 61: 70-536 test part 1

' Calls CaseInsensitiveComparer.Compare with the parameters reversed. Public Function Compare( ByVal x As Object, ByVal y As Object) As Integer _ Implements IComparer.Compare Return New CaseInsensitiveComparer().Compare(y, x) End Function 'IComparer.Compare

End Class 'myReverserClass

Public Shared Sub Main()

' Creates and initializes a new ArrayList. Dim myAL As New ArrayList() myAL.Add("The") myAL.Add("quick") myAL.Add("brown") myAL.Add("fox") myAL.Add("jumps") myAL.Add("over") myAL.Add("the") myAL.Add("lazy") myAL.Add("dog")

' Displays the values of the ArrayList. Console.WriteLine("The ArrayList initially contains the following values:") PrintIndexAndValues(myAL)

' Sorts the values of the ArrayList using the default comparer. myAL.Sort() Console.WriteLine("After sorting with the default comparer:") PrintIndexAndValues(myAL)

' Sorts the values of the ArrayList using the reverse case-insensitive comparer. Dim myComparer = New myReverserClass() myAL.Sort(myComparer) Console.WriteLine("After sorting with the reverse case-insensitive comparer:") PrintIndexAndValues(myAL)

End Sub 'Main

Public Shared Sub PrintIndexAndValues(myList As IEnumerable) Dim i As Integer = 0 Dim obj As [Object] For Each obj In myList Console.WriteLine(vbTab + "[{0}]:" + vbTab + "{1}", i, obj) i = i + 1 Next obj Console.WriteLine() End Sub 'PrintIndexAndValues

Page 62: 70-536 test part 1

End Class 'SamplesArrayList

'This code produces the following output.'The ArrayList initially contains the following values:' [0]: The' [1]: quick' [2]: brown' [3]: fox' [4]: jumps' [5]: over' [6]: the' [7]: lazy' [8]: dog''After sorting with the default comparer:' [0]: brown' [1]: dog' [2]: fox' [3]: jumps' [4]: lazy' [5]: over' [6]: quick' [7]: the' [8]: The''After sorting with the reverse case-insensitive comparer:' [0]: the' [1]: The' [2]: quick' [3]: over' [4]: lazy' [5]: jumps' [6]: fox' [7]: dog' [8]: brown

C# using System;using System.Collections;

public class SamplesArrayList {

public class myReverserClass : IComparer {

// Calls CaseInsensitiveComparer.Compare with the parameters reversed. int IComparer.Compare( Object x, Object y ) { return( (new CaseInsensitiveComparer()).Compare( y, x ) ); }

Page 63: 70-536 test part 1

}

public static void Main() {

// Creates and initializes a new ArrayList. ArrayList myAL = new ArrayList(); myAL.Add( "The" ); myAL.Add( "quick" ); myAL.Add( "brown" ); myAL.Add( "fox" ); myAL.Add( "jumps" ); myAL.Add( "over" ); myAL.Add( "the" ); myAL.Add( "lazy" ); myAL.Add( "dog" );

// Displays the values of the ArrayList. Console.WriteLine( "The ArrayList initially contains the following values:" ); PrintIndexAndValues( myAL );

// Sorts the values of the ArrayList using the default comparer. myAL.Sort(); Console.WriteLine( "After sorting with the default comparer:" ); PrintIndexAndValues( myAL );

// Sorts the values of the ArrayList using the reverse case-insensitive comparer. IComparer myComparer = new myReverserClass(); myAL.Sort( myComparer ); Console.WriteLine( "After sorting with the reverse case-insensitive comparer:" ); PrintIndexAndValues( myAL );

}

public static void PrintIndexAndValues( IEnumerable myList ) { int i = 0; foreach ( Object obj in myList ) Console.WriteLine( "\t[{0}]:\t{1}", i++, obj ); Console.WriteLine(); }

}

/* This code produces the following output.The ArrayList initially contains the following values: [0]: The [1]: quick

Page 64: 70-536 test part 1

[2]: brown [3]: fox [4]: jumps [5]: over [6]: the [7]: lazy [8]: dog

After sorting with the default comparer: [0]: brown [1]: dog [2]: fox [3]: jumps [4]: lazy [5]: over [6]: quick [7]: the [8]: The

After sorting with the reverse case-insensitive comparer: [0]: the [1]: The [2]: quick [3]: over [4]: lazy [5]: jumps [6]: fox [7]: dog [8]: brown */

Constructors and Destructors

Constructors When a class is declared as in the following code, we only say that we want to have an instance of the class in our program. We have not yet created the class, only that we have allocated some program memory.

Car FordCapri;To do this we must instantiate an instance of the class, this is done using the new keyword, as in the following code:

Car FordCapri = new Car();You can see that after the new keyword we called a method with the same name as the class. This is called its constructor. A constructor is a method that is invoked upon instantiation of a class, known as "instance constructors". An instance constructor is a member that implements the actions required to initialize an instance of a class.

Every constructor has the same defining layout:

Page 65: 70-536 test part 1

[access-modifier] constructor_name (parameters){ // constructor body}The access-modifier is optional and can be private, public, protected or internal. If no modifier is supplied, then the default is private.

The constructor_name of a constructor must be the same as the name of the class.

A constructor can take zero or more arguments as parameters. A constructor with zero arguments (that is no-arguments) is known as a default constructor. A class can have more than one constructor, by giving each constructor a different set of parameters. This gives the user the ability to initialise the object in more than one way.

The constructor body can be used to initialise the object into a known starting state.

In, general, a constructor’s access modifier is public, this is because the class that is creating an instance of this class, needs to be able to access the constructor of the class.

public Car(){ . . .}

Static constructors A static constructor is used to initialize any static data members. It is called automatically before the first instance is created or any static members are referenced. A static constructor does not take access modifiers or have parameters and therefore cannot be called using the new keyword.

Static constructors have the following properties:

A static constructor does not take access modifiers or have parameters. Accessibility defaults to the same accessibility as the class itself. A static constructor is called automatically to initialize the class before the first instance is created or any static members are referenced. A static constructor cannot be called directly. A static constructor cannot be overloaded. A static constructor is not inheritable.

Destructors Each class also requires a destructor, this is the code that is called to clean up the object when it has been finished with. However, if you do not provide one, then the Garbage Collector will deal with freeing up the memory for you. Any object that you create in the class, should be deleted from the class as a general rule of thumb.

A destructor is defined pretty much in the same way as a constructor, but has a tilde (~) in front of the method name.

public ~Car()

Page 66: 70-536 test part 1

{ . . .}Destructors have the following properties:

Destructors cannot be inherited or overloaded. Destructors cannot be called. They are invoked automatically. A destructor does not take modifiers or have parameters.

Note

Empty destructors should not be used. When a class contains a destructor, an entry is created in the Finalize queue. When the destructor is called, the garbage collector is invoked to process the queue. If the destructor is empty, this simply results in a needless loss of performance. You should only create a destructor if it is really necessary. Otherwise let the memory management clean up behind you.

Destructors

Destructors are used to destruct instances of classes.

Remarks Destructors cannot be defined in structs. They are only used with classes.

A class can only have one destructor.

Destructors cannot be inherited or overloaded.

Destructors cannot be called. They are invoked automatically.

A destructor does not take modifiers or have parameters.

For example, the following is a declaration of a destructor for the class Car:

class Car{ ~Car() // destructor { // cleanup statements... }}

The destructor implicitly calls Finalize on the base class of the object. Therefore, the previous destructor code is implicitly translated to the following code:

protected override void Finalize(){ try

Page 67: 70-536 test part 1

{ // Cleanup statements... } finally { base.Finalize(); }}This means that the Finalize method is called recursively for all instances in the inheritance chain, from the most-derived to the least-derived.

Note: Empty destructors should not be used. When a class contains a destructor, an entry is created in the Finalize queue. When the destructor is called, the garbage collector is invoked to process the queue. If the destructor is empty, this just causes a needless loss of performance. The programmer has no control over when the destructor is called because this is determined by the garbage collector. The garbage collector checks for objects that are no longer being used by the application. If it considers an object eligible for destruction, it calls the destructor (if any) and reclaims the memory used to store the object. Destructors are also called when the program exits.

It is possible to force garbage collection by calling Collect, but most of the time, this should be avoided because it may create performance issues.

Using Destructors to Release Resources In general, C# does not require as much memory management as is needed when you develop with a language that does not target a runtime with garbage collection. This is because the .NET Framework garbage collector implicitly manages the allocation and release of memory for your objects. However, when your application encapsulates unmanaged resources such as windows, files, and network connections, you should use destructors to free those resources. When the object is eligible for destruction, the garbage collector runs the Finalize method of the object.

Explicit Release of Resources If your application is using an expensive external resource, we also recommend that you provide a way to explicitly release the resource before the garbage collector frees the object. You do this by implementing a Dispose method from the IDisposable interface that performs the necessary cleanup for the object. This can considerably improve the performance of the application. Even with this explicit control over resources, the destructor becomes a safeguard to clean up resources if the call to the Dispose method failed.

For more details about cleaning up resources, see the following topics:

Cleaning Up Unmanaged Resources

Implementing a Dispose Method

Page 68: 70-536 test part 1

using Statement (C# Reference)

Example The following example creates three classes that make a chain of inheritance. The class First is the base class, Second is derived from First, and Third is derived from Second. All three have destructors. In Main(), an instance of the most-derived class is created. When the program runs, notice that the destructors for the three classes are called automatically, and in order, from the most-derived to the least-derived.

C# class First{ ~First() { System.Diagnostics.Trace.WriteLine("First's destructor is called."); }}

class Second : First{ ~Second() { System.Diagnostics.Trace.WriteLine("Second's destructor is called."); }}

class Third : Second{ ~Third() { System.Diagnostics.Trace.WriteLine("Third's destructor is called."); }}

class TestDestructors{ static void Main() { Third t = new Third(); }

}/* Output (to VS Output Window): Third's destructor is called. Second's destructor is called. First's destructor is called.*/

Page 69: 70-536 test part 1

Instance Constructors

Instance constructors are used to create and initialize any instance member variables when you use the new expression to create an object of a class. To initialize a static class, or static variables in a non-static class, you must define a static constructor. For more information, see Static Constructors (C# Programming Guide).

The following example shows an instance constructor:

class CoOrds{ public int x, y;

// constructor public CoOrds() { x = 0; y = 0; }}

Note: For clarity, this class contains public fields. The use of public fields is not a recommended programming practice because it allows any method anywhere in a program unrestricted and unverified access to an object's inner workings. Data members should generally be private, and should be accessed only through class methods and properties.

This instance constructor is called whenever an object based on the CoOrds class is created. A constructor like this one, which takes no arguments, is called a default constructor. However, it is often useful to provide additional constructors. For example, we can add a constructor to the CoOrds class that allows us to specify the initial values for the data members:

// tcA constructor with two arguments:public CoOrds(int x, int y){ this.x = x; this.y = y;}

This allows CoOrd objects to be created with default or specific initial values, like this:

CoOrds p1 = new CoOrds();CoOrds p2 = new CoOrds(5, 3);

If a class does not have a default constructor, one is automatically generated and default values are used to initialize the object fields, for example, an int is initialized to 0. For

Page 70: 70-536 test part 1

more information on default values, see Default Values Table (C# Reference). Therefore, because the CoOrds class default constructor initializes all data members to zero, it can be removed altogether without changing how the class works. A complete example using multiple constructors is provided in Example 1 later in this topic, and an example of an automatically generated constructor is provided in Example 2.

Instance constructors can also be used to call the instance constructors of base classes. The class constructor can invoke the constructor of the base class through the initializer, as follows:

class Circle : Shape{ public Circle(double radius) : base(radius, 0) { }}

In this example, the Circle class passes values representing radius and height to the constructor provided by Shape from which Circle is derived. A complete example using Shape and Circle appears in this topic as Example 3.

Example 1 The following example demonstrates a class with two class constructors, one without arguments and one with two arguments.

class CoOrds{ public int x, y;

// Default constructor: public CoOrds() { x = 0; y = 0; }

// tcA constructor with two arguments: public CoOrds(int x, int y) { this.x = x; this.y = y; }

// Override the ToString method: public override string ToString() { return (String.Format("({0},{1})", x, y));

Page 71: 70-536 test part 1

}}

class MainClass{ static void Main() { CoOrds p1 = new CoOrds(); CoOrds p2 = new CoOrds(5, 3);

// Display the results using the overriden ToString method: Console.WriteLine("CoOrds #1 at {0}", p1); Console.WriteLine("CoOrds #2 at {0}", p2); Console.ReadKey(); }}/* Output: CoOrds #1 at (0,0) CoOrds #2 at (5,3) */

Example 2 In this example, the class Person does not have any constructors, in which case, a default constructor is automatically provided and the fields are initialized to their default values.

public class Person{ public int age; public string name;}

class TestPerson{ static void Main() { Person person = new Person();

Console.WriteLine("Name: {0}, Age: {1}", person.name, person.age); // Keep the console window open in debug mode. Console.WriteLine("Press any key to exit."); Console.ReadKey(); }}// Output: Name: , Age: 0

Notice that the default value of age is 0 and the default value of name is null. For more information on default values, see Default Values Table (C# Reference).

Page 72: 70-536 test part 1

Example 3 The following example demonstrates using the base class initializer. The Circle class is derived from the general class Shape, and the Cylinder class is derived from the Circle class. The constructor on each derived class is using its base class initializer.

abstract class Shape{ public const double pi = Math.PI; protected double x, y;

public Shape(double x, double y) { this.x = x; this.y = y; }

public abstract double Area();}

class Circle : Shape{ public Circle(double radius) : base(radius, 0) { } public override double Area() { return pi * x * x; }}

class Cylinder : Circle{ public Cylinder(double radius, double height) : base(radius) { y = height; }

public override double Area() { return (2 * base.Area()) + (2 * pi * x * y); }}

class TestShapes{ static void Main()

Page 73: 70-536 test part 1

{ double radius = 2.5; double height = 3.0;

Circle ring = new Circle(radius); Cylinder tube = new Cylinder(radius, height);

Console.WriteLine("Area of the circle = {0:F2}", ring.Area()); Console.WriteLine("Area of the cylinder = {0:F2}", tube.Area());

// Keep the console window open in debug mode. Console.WriteLine("Press any key to exit."); Console.ReadKey(); }}/* Output: Area of the circle = 19.63 Area of the cylinder = 86.39*/

Private Constructors A private constructor is a special instance constructor. It is generally used in classes that contain static members only. If a class has one or more private constructors and no public constructors, other classes (except nested classes) cannot create instances of this class. For example:

class NLog{ // Private Constructor: private NLog() { }

public static double e = Math.E; //2.71828...}

The declaration of the empty constructor prevents the automatic generation of a default constructor. Note that if you do not use an access modifier with the constructor it will still be private by default. However, the private modifier is usually used explicitly to make it clear that the class cannot be instantiated.

Private constructors are used to prevent creating instances of a class when there are no instance fields or methods, such as the Math class, or when a method is called to obtain an instance of a class. If all the methods in the class are static, consider making the complete class static. For more information see Static Classes and Static Class Members (C# Programming Guide).

Example The following is an example of a class using a private constructor.

public class Counter

Page 74: 70-536 test part 1

{ private Counter() { } public static int currentCount; public static int IncrementCount() { return ++currentCount; }}

class TestCounter{ static void Main() { // If you uncomment the following statement, it will generate // an error because the constructor is inaccessible: // Counter aCounter = new Counter(); // Error

Counter.currentCount = 100; Counter.IncrementCount(); Console.WriteLine("New count: {0}", Counter.currentCount);

// Keep the console window open in debug mode. Console.WriteLine("Press any key to exit."); Console.ReadKey(); }}// Output: New count: 101

Notice that if you uncomment the following statement from the example, it will generate an error because the constructor is inaccessible because of its protection level:

// Counter aCounter = new Counter(); // Error

Static Constructors

A static constructor is used to initialize any static data, or to perform a particular action that needs performed once only. It is called automatically before the first instance is created or any static members are referenced.

class SimpleClass{ // Static variable that must be initialized at run time. static readonly long baseline;

// Static constructor is called at most one time, before any // instance constructor is invoked or member is accessed. static SimpleClass() { baseline = DateTime.Now.Ticks;

Page 75: 70-536 test part 1

}}

Static constructors have the following properties:

A static constructor does not take access modifiers or have parameters.

A static constructor is called automatically to initialize the class before the first instance is created or any static members are referenced.

A static constructor cannot be called directly.

The user has no control on when the static constructor is executed in the program.

A typical use of static constructors is when the class is using a log file and the constructor is used to write entries to this file.

Static constructors are also useful when creating wrapper classes for unmanaged code, when the constructor can call the LoadLibrary method.

If a static constructor throws an exception, the runtime will not invoke it a second time, and the type will remain uninitialized for the lifetime of the application domain in which your program is running.

Example In this example, the class Bus has a static constructor and one static member, Drive(). When Drive() is called, the static constructor is invoked to initialize the class.

public class Bus { // static variable used by all Bus instances // Represents the time the first bus of the day starts its route. protected static readonly DateTime globalStartTime;

// Instance readonly variable protected int RouteNumber { get; set; }

// Static constructor to initialize static variable. // It is invoked before the first instance constructor is called. static Bus() { globalStartTime = DateTime.Now; Console.WriteLine("Static ctor sets global start time to {0}", globalStartTime.ToLongTimeString()); }

// Instance constructor

Page 76: 70-536 test part 1

public Bus(int routeNum) { RouteNumber = routeNum; Console.WriteLine("{0} is created.", RouteNumber); }

// Instance method. public void Drive() { TimeSpan elapsedTime = DateTime.Now - globalStartTime;

// For demonstration purposes we treat milliseconds as minutes to // simulate actual bus times. Do not do this in your actual bus schedule program! Console.WriteLine("{0} is starting its route {1:N2} minutes after global start time {2}.", this.RouteNumber, elapsedTime.TotalMilliseconds, globalStartTime.ToShortTimeString()); } }

class TestBus { static void Main() {

Bus bus = new Bus(71); bus.Drive();

// Wait for next bus to warm up. System.Threading.Thread.Sleep(25);

Bus bus2 = new Bus(72); bus2.Drive();

// Keep the console window open in debug mode. System.Console.WriteLine("Press any key to exit."); System.Console.ReadKey(); } } /* Output: Static ctor sets global start time to 10:04:08 AM 71 is created. 71 is starting its route 21.00 minutes after global start time 10:04 AM. 72 is created. 72 is starting its route 46.00 minutes after global start time 10:04 AM. */

Page 77: 70-536 test part 1

Using Constructors

Constructors are class methods that are executed when an object of a given type is created. Constructors have the same name as the class, and usually initialize the data members of the new object.

In the following example, a class named Taxi is defined by using a simple constructor. This class is then instantiated with the new operator. The Taxi constructor is invoked by the new operator immediately after memory is allocated for the new object.

public class Taxi{ public bool isInitialized; public Taxi() { isInitialized = true; }}

class TestTaxi{ static void Main() { Taxi t = new Taxi(); Console.WriteLine(t.isInitialized); }}

A constructor that takes no parameters is called a default constructor. Default constructors are invoked whenever an object is instantiated by using the new operator and no arguments are provided to new. For more information, see Instance Constructors (C# Programming Guide).

Unless the class is static, classes without constructors are given a public default constructor by the C# compiler in order to enable class instantiation. For more information, see Static Classes and Static Class Members (C# Programming Guide).

You can prevent a class from being instantiated by making the constructor private, as follows:

class NLog{ // Private Constructor: private NLog() { }

public static double e = Math.E; //2.71828...}

Page 78: 70-536 test part 1

For more information, see Private Constructors (C# Programming Guide).

Constructors for struct types resemble class constructors, but structs cannot contain an explicit default constructor because one is provided automatically by the compiler. This constructor initializes each field in the struct to the default values. For more information, see Default Values Table (C# Reference). However, this default constructor is only invoked if the struct is instantiated with new. For example, this code uses the default constructor for Int32, so that you are assured that the integer is initialized:

int i = new int();Console.WriteLine(i);The following code, however, causes Compiler Error CS0165 because it does not use new, and because it tries to use an object that has not been initialized:

int i;Console.WriteLine(i);Alternatively, objects based on structs (including all built-in numeric types) can be initialized or assigned and then used as in the following example:

int a = 44; // Initialize the value type...int b;b = 33; // Or assign it before using it.Console.WriteLine("{0}, {1}", a, b);So calling the default constructor for a value type is not required.

Both classes and structs can define constructors that take parameters. Constructors that take parameters must be called through a new statement or a base statement. Classes and structs can also define multiple constructors, and neither is required to define a default constructor. For example:

public class Employee{ public int salary;

public Employee(int annualSalary) { salary = annualSalary; }

public Employee(int weeklySalary, int numberOfWeeks) { salary = weeklySalary * numberOfWeeks; }}

This class can be created by using either of the following statements:

Page 79: 70-536 test part 1

Employee e1 = new Employee(30000);Employee e2 = new Employee(500, 52);

A constructor can use the base keyword to call the constructor of a base class. For example:

public class Manager : Employee{ public Manager(int annualSalary) : base(annualSalary) { //Add further instructions here. }}

In this example, the constructor for the base class is called before the block for the constructor is executed. The base keyword can be used with or without parameters. Any parameters to the constructor can be used as parameters to base, or as part of an expression. For more information, see base (C# Reference).

In a derived class, if a base-class constructor is not called explicitly by using the base keyword, the default constructor, if there is one, is called implicitly. This means that the following constructor declarations are effectively the same:

public Manager(int initialdata){ //Add further instructions here.}

public Manager(int initialdata) : base(){ //Add further instructions here.}

If a base class does not offer a default constructor, the derived class must make an explicit call to a base constructor by using base.

A constructor can invoke another constructor in the same object by using the this keyword. Like base, this can be used with or without parameters, and any parameters in the constructor are available as parameters to this, or as part of an expression. For example, the second constructor in the previous example can be rewritten using this:

public Employee(int weeklySalary, int numberOfWeeks) : this(weeklySalary * numberOfWeeks){}

Page 80: 70-536 test part 1

The use of the this keyword in the previous example causes this constructor to be called:

public Employee(int annualSalary){ salary = annualSalary;}

Constructors can be marked as public, private, protected, internal, or protected internal. These access modifiers define how users of the class can construct the class. For more information, see Access Modifiers.

A constructor can be declared static by using the static keyword. Static constructors are called automatically, immediately before any static fields are accessed, and are generally used to initialize static class members

Copy ConstructorsCopying a class C# does not provide a copy constructor. If you create a new object and want to copy the values from an existing object, you have to write the appropriate method yourself. For example:

class Car{ private string plate; private int mileage; // Copy constructor. public Car(Car previousCar) { plate = previousCar.plate; mileage = previousCar.mileage; } // Instance constructor. public Car(string plate, int mileage) { this.plate = plate; this.mileage = mileage; } // Get accessor. public string Details { get { return "The car : " + plate + " has done "

Page 81: 70-536 test part 1

+ mileage.ToString() + " miles"; } }} class TestCar{ static void Main() { // Create a new car object. Car car1 = new Car("BB06 YUK", 40000); // Create another new object, copying car1. Car car2 = new Car(car1); System.Console.WriteLine(car2.Details); }}

An alternative This is a simple way to copy an object; however, an alternative method is to implement the ICloneable interface.

How to: Write a Copy Constructor (C# Programming Guide)

Unlike some languages, C# does not provide a copy constructor. If you create a new object and want to copy the values from an existing object, you have to write the appropriate method yourself.

Example In this example, the Person class contains a constructor that takes as the argument another object of type Person. The contents of the fields in this object are then assigned to the fields in the new object.

class Person{ private string name; private int age;

// Copy constructor. public Person(Person previousPerson) { name = previousPerson.name; age = previousPerson.age; }

// Instance constructor. public Person(string name, int age) { this.name = name;

Page 82: 70-536 test part 1

this.age = age; }

// Get accessor. public string Details { get { return name + " is " + age.ToString(); } }}

class TestPerson{ static void Main() { // Create a new person object. Person person1 = new Person("George", 40);

// Create another new object, copying person. Person person2 = new Person(person1); Console.WriteLine(person2.Details);

// Keep the console window open in debug mode. Console.WriteLine("Press any key to exit."); Console.ReadKey(); }}// Output: George is 40

Declaring ClassesA class is an abstract representation for some particular type of object. It can be described as a template or blueprint for an object, as opposed to the actual object itself. Thus, objects are an instance of a class - they come into existence at some specific time, persist for some duration, and then disappear when they are no longer needed. Classes are the abstract descriptions used by the system to create objects when called upon to do so.

Declaration [attributes] [modifiers] class identifier [:base-type]{body [;]}The attributes is optional and is used to hold additional declarative information.

The modifier is optional. The allowed modifiers are static, sealed, abstract, unsafe, public and internal. If no modifier is supplied then a default of internal is used.

The keyword class must be followed by an identifier that names the class.

Page 83: 70-536 test part 1

base-type may define any class other than System.Array, System.Delegate, System.MulticastDelegate, System.Enum or System.ValueType as the base class for this class. If a base class is not supplied, then the class will inherit from System.Object.

base-type may also specify the interfaces implemented by this class. The interfaces must be listed after the base class name (if specified) and must be separated by commas.

The body contains the member declarations.

[edit]A simple class The following code contains the minimum code for a class. Although this class will not actually do anything.

class SimpleObject{ public SimpleObject() { }}

Modifiers abstract - the class is created solely for the purpose of inheritance. You cannot create an instance of an abstract class.

sealed - the class cannot be inherited from.

static – the class can only contain static members.

unsafe - allows for unsafe constructs such as pointers. Requires the unsafe compiler option.

public - any item in the current assembly or any assembly that references it, can access this class.

internal - Any item in the current assembly can access this class.

The access levels protected and private are only allowed on nested classes.

Abstract and Sealed Classes and Class Members

The abstract keyword enables you to create classes and class members that are incomplete and must be implemented in a derived class.

The sealed keyword enables you to prevent the inheritance of a class or certain class members that were previously marked virtual.

Abstract Classes and Class Members Classes can be declared as abstract by putting the keyword abstract before the class definition. For example:

Page 84: 70-536 test part 1

public abstract class A{ // Class members here.}

An abstract class cannot be instantiated. The purpose of an abstract class is to provide a common definition of a base class that multiple derived classes can share. For example, a class library may define an abstract class that is used as a parameter to many of its functions, and require programmers using that library to provide their own implementation of the class by creating a derived class.

Abstract classes may also define abstract methods. This is accomplished by adding the keyword abstract before the return type of the method. For example:

public abstract class A{ public abstract void DoWork(int i);}

Abstract methods have no implementation, so the method definition is followed by a semicolon instead of a normal method block. Derived classes of the abstract class must implement all abstract methods. When an abstract class inherits a virtual method from a base class, the abstract class can override the virtual method with an abstract method. For example:

// compile with: /target:librarypublic class D{ public virtual void DoWork(int i) { // Original implementation. }}

public abstract class E : D{ public abstract override void DoWork(int i);}

public class F : E{ public override void DoWork(int i) { // New implementation. }}

Page 85: 70-536 test part 1

If a virtual method is declared abstract, it is still virtual to any class inheriting from the abstract class. A class inheriting an abstract method cannot access the original implementation of the method—in the previous example, DoWork on class F cannot call DoWork on class D. In this way, an abstract class can force derived classes to provide new method implementations for virtual methods.

Sealed Classes and Class Members Classes can be declared as sealed by putting the keyword sealed before the class definition. For example:

public sealed class D{ // Class members here.}

A sealed class cannot be used as a base class. For this reason, it cannot also be an abstract class. Sealed classes prevent derivation. Because they can never be used as a base class, some run-time optimizations can make calling sealed class members slightly faster.

A class member, method, field, property, or event, on a derived class that is overriding a virtual member of the base class can declare that member as sealed. This negates the virtual aspect of the member for any further derived class. This is accomplished by putting the sealed keyword before the override keyword in the class member declaration. For example:

public class D : C{ public sealed override void DoWork() { }}

internalThe internal keyword is an access modifier for types and type members. Internal types or members are accessible only within files in the same assembly, as in this example:

public class BaseClass { // Only accessible within the same assembly internal static int x = 0;}For a comparison of internal with the other access modifiers, see Accessibility Levels (C# Reference) and Access Modifiers (C# Programming Guide).

For more information about assemblies, see Assemblies and the Global Assembly Cache (C# Programming Guide).

A common use of internal access is in component-based development because it enables a group of components to cooperate in a private manner without being exposed to the rest

Page 86: 70-536 test part 1

of the application code. For example, a framework for building graphical user interfaces could provide Control and Form classes that cooperate by using members with internal access. Since these members are internal, they are not exposed to code that is using the framework.

It is an error to reference a type or a member with internal access outside the assembly within which it was defined.

Note: An internal virtual method can be overridden in some languages, such as textual Microsoft intermediate language (MSIL) using Ilasm.exe, even though it cannot be overridden by using C#. Example This example contains two files, Assembly1.cs and Assembly1_a.cs. The first file contains an internal base class, BaseClass. In the second file, an attempt to instantiate BaseClass will produce an error.

// Assembly1.cs// Compile with: /target:libraryinternal class BaseClass { public static int intM = 0;}// Assembly1_a.cs// Compile with: /reference:Assembly1.dllclass TestAccess { static void Main() { BaseClass myBase = new BaseClass(); // CS0122 }}In this example, use the same files you used in example 1, and change the accessibility level of BaseClass to public. Also change the accessibility level of the member IntM to internal. In this case, you can instantiate the class, but you cannot access the internal member.

// Assembly2.cs// Compile with: /target:librarypublic class BaseClass { internal static int intM = 0;}// Assembly2_a.cs// Compile with: /reference:Assembly1.dllpublic class TestAccess { static void Main()

Page 87: 70-536 test part 1

{ BaseClass myBase = new BaseClass(); // Ok. BaseClass.intM = 444; // CS0117 }}

public

The public keyword is an access modifier for types and type members. Public access is the most permissive access level. There are no restrictions on accessing public members, as in this example:

class SampleClass{ public int x; // No access restrictions.}See Access Modifiers (C# Programming Guide) and Accessibility Levels (C# Reference) for more information.

Example In the following example, two classes are declared, Point and MainClass. The public members x and y of Point are accessed directly from MainClass.

class PointTest{ public int x; public int y;}

class MainClass4{ static void Main() { PointTest p = new PointTest(); // Direct access to public members: p.x = 10; p.y = 15; Console.WriteLine("x = {0}, y = {1}", p.x, p.y); }}// Output: x = 10, y = 15

If you change the public access level to private or protected, you will get the error message:

'Point.y' is inaccessible due to its protection level.

unsafe

Page 88: 70-536 test part 1

The unsafe keyword denotes an unsafe context, which is required for any operation involving pointers. For more information, see Unsafe Code and Pointers (C# Programming Guide).

You can use the unsafe modifier in the declaration of a type or a member. The entire textual extent of the type or member is therefore considered an unsafe context. For example, the following is a method declared with the unsafe modifier:

unsafe static void FastCopy(byte[] src, byte[] dst, int count){ // Unsafe context: can use pointers here.}The scope of the unsafe context extends from the parameter list to the end of the method, so pointers can also be used in the parameter list:

unsafe static void FastCopy ( byte* ps, byte* pd, int count ) {...}You can also use an unsafe block to enable the use of an unsafe code inside this block. For example:

unsafe{ // Unsafe context: can use pointers here.}To compile unsafe code, you must specify the /unsafe compiler option. Unsafe code is not verifiable by the common language runtime.

Example // compile with: /unsafe

class UnsafeTest{ // Unsafe method: takes pointer to int: unsafe static void SquarePtrParam(int* p) { *p *= *p; }

unsafe static void Main() { int i = 5; // Unsafe method: uses address-of operator (&): SquarePtrParam(&i); Console.WriteLine(i); }}// Output: 25

Unsafe Code and Pointers

Page 89: 70-536 test part 1

To maintain type safety and security, C# does not support pointer arithmetic, by default. However, by using the unsafe keyword, you can define an unsafe context in which pointers can be used. For more information about pointers, see the topic Pointer types.

Note: In the common language runtime (CLR), unsafe code is referred to as unverifiable code. Unsafe code in C# is not necessarily dangerous; it is just code whose safety cannot be verified by the CLR. The CLR will therefore only execute unsafe code if it is in a fully trusted assembly. If you use unsafe code, it is your responsibility to ensure that your code does not introduce security risks or pointer errors. For more information, see Security (C# Programming Guide). Unsafe Code Overview Unsafe code has the following properties:

Methods, types, and code blocks can be defined as unsafe.

In some cases, unsafe code may increase an application's performance by removing array bounds checks.

Unsafe code is required when you call native functions that require pointers.

Using unsafe code introduces security and stability risks.

In order for C# to compile unsafe code, the application must be compiled with /unsafe.

DelegateSummary A delegate is basically a reference to a method. A delegate can be passed like any other variable. This allows the method to be called anonymously, without calling the method directly.

In C#, delegates are the basis for events.

For example:

A object can create a delegate that refers to one of its private methods. Then the object can pass that delegate to another object. The second object could then call that private method without knowing anything about it (loose-binding).

Code Examples These examples demonstrate delegates that are not used for events

Naming convention used in these Code Examples:

Name delegate types with a suffix of "Callback"

Name delegate instances with a previx of "do"

Page 90: 70-536 test part 1

do stands for both "do something" and "delegate object"

Example Names:

// Delegate Declarationpublic delegate void AcceptCallback(); // Delegate Instance AcceptCallback doAccept;Declare a void delegate that takes no parameters:

public delegate void ExecuteCallback();Declare a delegate that has parameters and returns a value:

public delegate int AccountComparisonCallback( Account a, Account b );Declare a generic delegate that has parameters and returns a value:

public delegate int CompareCallback<T>( T a, T b );Create a delegate object that refers to a method called Compare:

AccountComparisonCallback doComparison = new AccountComparisonCallback( Compare );Call a delegate

// (Outside the class)// The delegate type declarationpublic delegate int AccountComparisonCallback( Account a, Account b ); // (Inside the class)// The delegate instanceprivate AccountComparisonCallback _doComparison; // This method calls the comparison delegate safely// Which simplifies the call so other class methods // can easily call the delegateprivate int CallComparison( Account a, Account b ){// Check for null before calling a delegateif( _doComparison != null ){// Call the delegate like a methodreturn _doComparison( a, b );}// If the delegate is null, return 0else{return 0;}}

Page 91: 70-536 test part 1

Create a delegate object and pass it as a parameter

// The AccountComparison Delegatepublic delegate int AccountComparisonCallback( Account a, Account b ); public class AccountSorter{// Declare a method that has the same signature as the delegateprivate int Compare( Account a, Account b ){// ...}

// Declare a method that uses the delegatepublic void Sort( List<Account> accounts ){// Create the delegate object that refers to the Compare methodAccountComparisonCallback doComparison = new AccountComparisonCallback( Compare );

// Pass the delegate as an argument to a methodaccounts.Sort( doComparison );

// Explaination:// Inside the Sort method, the delegate will be called// which calls the private Compare method to which it refers// In this way the Sort method is able to call a method without // knowing anything about the actual method}}

DictionaryBase classes

DictionaryBase Class

Provides the abstract base class for a strongly typed collection of key/value pairs.

Namespace: System.CollectionsAssembly: mscorlib (in mscorlib.dll) Syntax Visual Basic (Declaration)<SerializableAttribute> _<ComVisibleAttribute(True)> _Public MustInherit Class DictionaryBase _ Implements IDictionary, ICollection, IEnumerableVisual Basic (Usage)Dim instance As DictionaryBaseC#[SerializableAttribute]

Page 92: 70-536 test part 1

[ComVisibleAttribute(true)]public abstract class DictionaryBase : IDictionary, ICollection, IEnumerable

Remarks The foreach statement of the C# language (for each in Visual Basic) requires the type of each element in the collection. Since each element of the DictionaryBase is a key/value pair, the element type is not the type of the key or the type of the value. Instead, the element type is DictionaryEntry. For example:

C# foreach (DictionaryEntry de in myDictionary) {...}

Visual Basic Copy CodeFor Each de As Dictionary Entry In myDictionary ...Next myDE

vb#c#The foreach statement is a wrapper around the enumerator, which only allows reading from, not writing to, the collection.

Note: Because keys can be inherited and their behavior changed, their absolute uniqueness cannot be guaranteed by comparisons using the Equals method.

Notes to Implementers: This base class is provided to make it easier for implementers to create a strongly typed custom collection. Implementers are encouraged to extend this base class instead of creating their own.

Members of this base class are protected and are intended to be used through a derived class only.

Examples The following code example implements the DictionaryBase class and uses that implementation to create a dictionary of String keys and values that have a Length of 5 characters or less.

Visual Basic Copy CodeImports SystemImports System.Collections

Public Class ShortStringDictionary Inherits DictionaryBase

Default Public Property Item(key As String) As String

Page 93: 70-536 test part 1

Get Return CType(Dictionary(key), String) End Get Set Dictionary(key) = value End Set End Property

Public ReadOnly Property Keys() As ICollection Get Return Dictionary.Keys End Get End Property

Public ReadOnly Property Values() As ICollection Get Return Dictionary.Values End Get End Property

Public Sub Add(key As String, value As String) Dictionary.Add(key, value) End Sub 'Add

Public Function Contains(key As String) As Boolean Return Dictionary.Contains(key) End Function 'Contains

Public Sub Remove(key As String) Dictionary.Remove(key) End Sub 'Remove

Protected Overrides Sub OnInsert(key As Object, value As Object) If Not GetType(System.String).IsAssignableFrom(key.GetType()) Then Throw New ArgumentException("key must be of type String.", "key") Else Dim strKey As String = CType(key, String) If strKey.Length > 5 Then Throw New ArgumentException("key must be no more than 5 characters in length.", "key") End If End If If Not GetType(System.String).IsAssignableFrom(value.GetType()) Then Throw New ArgumentException("value must be of type String.", "value") Else Dim strValue As String = CType(value, String) If strValue.Length > 5 Then Throw New ArgumentException("value must be no more than 5 characters in length.", "value")

Page 94: 70-536 test part 1

End If End If End Sub 'OnInsert

Protected Overrides Sub OnRemove(key As Object, value As Object) If Not GetType(System.String).IsAssignableFrom(key.GetType()) Then Throw New ArgumentException("key must be of type String.", "key") Else Dim strKey As String = CType(key, String) If strKey.Length > 5 Then Throw New ArgumentException("key must be no more than 5 characters in length.", "key") End If End If End Sub 'OnRemove

Protected Overrides Sub OnSet(key As Object, oldValue As Object, newValue As Object) If Not GetType(System.String).IsAssignableFrom(key.GetType()) Then Throw New ArgumentException("key must be of type String.", "key") Else Dim strKey As String = CType(key, String) If strKey.Length > 5 Then Throw New ArgumentException("key must be no more than 5 characters in length.", "key") End If End If If Not GetType(System.String).IsAssignableFrom(newValue.GetType()) Then Throw New ArgumentException("newValue must be of type String.", "newValue") Else Dim strValue As String = CType(newValue, String) If strValue.Length > 5 Then Throw New ArgumentException("newValue must be no more than 5 characters in length.", "newValue") End If End If End Sub 'OnSet

Protected Overrides Sub OnValidate(key As Object, value As Object) If Not GetType(System.String).IsAssignableFrom(key.GetType()) Then Throw New ArgumentException("key must be of type String.", "key") Else Dim strKey As String = CType(key, String) If strKey.Length > 5 Then Throw New ArgumentException("key must be no more than 5 characters in length.", "key") End If End If If Not GetType(System.String).IsAssignableFrom(value.GetType()) Then Throw New ArgumentException("value must be of type String.", "value")

Page 95: 70-536 test part 1

Else Dim strValue As String = CType(value, String) If strValue.Length > 5 Then Throw New ArgumentException("value must be no more than 5 characters in length.", "value") End If End If End Sub 'OnValidate

End Class 'ShortStringDictionary

Public Class SamplesDictionaryBase

Public Shared Sub Main()

' Creates and initializes a new DictionaryBase. Dim mySSC As New ShortStringDictionary()

' Adds elements to the collection. mySSC.Add("One", "a") mySSC.Add("Two", "ab") mySSC.Add("Three", "abc") mySSC.Add("Four", "abcd") mySSC.Add("Five", "abcde")

' Display the contents of the collection using For Each. This is the preferred method. Console.WriteLine("Contents of the collection (using For Each):") PrintKeysAndValues1(mySSC)

' Display the contents of the collection using the enumerator. Console.WriteLine("Contents of the collection (using enumerator):") PrintKeysAndValues2(mySSC)

' Display the contents of the collection using the Keys property and the Item property. Console.WriteLine("Initial contents of the collection (using Keys and Item):") PrintKeysAndValues3(mySSC)

' Tries to add a value that is too long. Try mySSC.Add("Ten", "abcdefghij") Catch e As ArgumentException Console.WriteLine(e.ToString()) End Try

' Tries to add a key that is too long. Try mySSC.Add("Eleven", "ijk") Catch e As ArgumentException Console.WriteLine(e.ToString())

Page 96: 70-536 test part 1

End Try

Console.WriteLine()

' Searches the collection with Contains. Console.WriteLine("Contains ""Three"": {0}", mySSC.Contains("Three")) Console.WriteLine("Contains ""Twelve"": {0}", mySSC.Contains("Twelve")) Console.WriteLine()

' Removes an element from the collection. mySSC.Remove("Two")

' Displays the contents of the collection. Console.WriteLine("After removing ""Two"":") PrintKeysAndValues1(mySSC)

End Sub 'Main

' Uses the For Each statement which hides the complexity of the enumerator. ' NOTE: The For Each statement is the preferred way of enumerating the contents of a collection. Public Shared Sub PrintKeysAndValues1(myCol As ShortStringDictionary) Dim myDE As DictionaryEntry For Each myDE In myCol Console.WriteLine(" {0,-5} : {1}", myDE.Key, myDE.Value) Next myDE Console.WriteLine() End Sub 'PrintKeysAndValues1

' Uses the enumerator. ' NOTE: The For Each statement is the preferred way of enumerating the contents of a collection. Public Shared Sub PrintKeysAndValues2(myCol As ShortStringDictionary) Dim myDE As DictionaryEntry Dim myEnumerator As System.Collections.IEnumerator = myCol.GetEnumerator() While myEnumerator.MoveNext() If Not (myEnumerator.Current Is Nothing) Then myDE = CType(myEnumerator.Current, DictionaryEntry) Console.WriteLine(" {0,-5} : {1}", myDE.Key, myDE.Value) End If End While Console.WriteLine() End Sub 'PrintKeysAndValues2

' Uses the Keys property and the Item property. Public Shared Sub PrintKeysAndValues3(myCol As ShortStringDictionary)

Page 97: 70-536 test part 1

Dim myKeys As ICollection = myCol.Keys Dim k As String For Each k In myKeys Console.WriteLine(" {0,-5} : {1}", k, myCol(k)) Next k Console.WriteLine() End Sub 'PrintKeysAndValues3

End Class 'SamplesDictionaryBase

'This code produces the following output.''Contents of the collection (using For Each):' Three : abc' Five : abcde' Two : ab' One : a' Four : abcd''Contents of the collection (using enumerator):' Three : abc' Five : abcde' Two : ab' One : a' Four : abcd''Initial contents of the collection (using Keys and Item):' Three : abc' Five : abcde' Two : ab' One : a' Four : abcd''System.ArgumentException: value must be no more than 5 characters in length.'Parameter name: value' at ShortStringDictionary.OnValidate(Object key, Object value)' at System.Collections.DictionaryBase.System.Collections.IDictionary.Add(Object key, Object value)' at SamplesDictionaryBase.Main()'System.ArgumentException: key must be no more than 5 characters in length.'Parameter name: key' at ShortStringDictionary.OnValidate(Object key, Object value)' at System.Collections.DictionaryBase.System.Collections.IDictionary.Add(Object key, Object value)' at SamplesDictionaryBase.Main()''Contains "Three": True'Contains "Twelve": False

Page 98: 70-536 test part 1

''After removing "Two":' Three : abc' Five : abcde' One : a' Four : abcd

C# using System;using System.Collections;

public class ShortStringDictionary : DictionaryBase {

public String this[ String key ] { get { return( (String) Dictionary[key] ); } set { Dictionary[key] = value; } }

public ICollection Keys { get { return( Dictionary.Keys ); } }

public ICollection Values { get { return( Dictionary.Values ); } }

public void Add( String key, String value ) { Dictionary.Add( key, value ); }

public bool Contains( String key ) { return( Dictionary.Contains( key ) ); }

public void Remove( String key ) { Dictionary.Remove( key ); }

protected override void OnInsert( Object key, Object value ) { if ( key.GetType() != typeof(System.String) )

Page 99: 70-536 test part 1

throw new ArgumentException( "key must be of type String.", "key" ); else { String strKey = (String) key; if ( strKey.Length > 5 ) throw new ArgumentException( "key must be no more than 5 characters in length.", "key" ); }

if ( value.GetType() != typeof(System.String) ) throw new ArgumentException( "value must be of type String.", "value" ); else { String strValue = (String) value; if ( strValue.Length > 5 ) throw new ArgumentException( "value must be no more than 5 characters in length.", "value" ); } }

protected override void OnRemove( Object key, Object value ) { if ( key.GetType() != typeof(System.String) ) throw new ArgumentException( "key must be of type String.", "key" ); else { String strKey = (String) key; if ( strKey.Length > 5 ) throw new ArgumentException( "key must be no more than 5 characters in length.", "key" ); } }

protected override void OnSet( Object key, Object oldValue, Object newValue ) { if ( key.GetType() != typeof(System.String) ) throw new ArgumentException( "key must be of type String.", "key" ); else { String strKey = (String) key; if ( strKey.Length > 5 ) throw new ArgumentException( "key must be no more than 5 characters in length.", "key" ); }

if ( newValue.GetType() != typeof(System.String) ) throw new ArgumentException( "newValue must be of type String.", "newValue" ); else { String strValue = (String) newValue; if ( strValue.Length > 5 ) throw new ArgumentException( "newValue must be no more than 5 characters in length.", "newValue" ); } }

Page 100: 70-536 test part 1

protected override void OnValidate( Object key, Object value ) { if ( key.GetType() != typeof(System.String) ) throw new ArgumentException( "key must be of type String.", "key" ); else { String strKey = (String) key; if ( strKey.Length > 5 ) throw new ArgumentException( "key must be no more than 5 characters in length.", "key" ); }

if ( value.GetType() != typeof(System.String) ) throw new ArgumentException( "value must be of type String.", "value" ); else { String strValue = (String) value; if ( strValue.Length > 5 ) throw new ArgumentException( "value must be no more than 5 characters in length.", "value" ); } }

}

public class SamplesDictionaryBase {

public static void Main() {

// Creates and initializes a new DictionaryBase. ShortStringDictionary mySSC = new ShortStringDictionary();

// Adds elements to the collection. mySSC.Add( "One", "a" ); mySSC.Add( "Two", "ab" ); mySSC.Add( "Three", "abc" ); mySSC.Add( "Four", "abcd" ); mySSC.Add( "Five", "abcde" );

// Display the contents of the collection using foreach. This is the preferred method. Console.WriteLine( "Contents of the collection (using foreach):" ); PrintKeysAndValues1( mySSC );

// Display the contents of the collection using the enumerator. Console.WriteLine( "Contents of the collection (using enumerator):" ); PrintKeysAndValues2( mySSC );

// Display the contents of the collection using the Keys property and the Item property. Console.WriteLine( "Initial contents of the collection (using Keys and Item):" ); PrintKeysAndValues3( mySSC );

// Tries to add a value that is too long.

Page 101: 70-536 test part 1

try { mySSC.Add( "Ten", "abcdefghij" ); } catch ( ArgumentException e ) { Console.WriteLine( e.ToString() ); }

// Tries to add a key that is too long. try { mySSC.Add( "Eleven", "ijk" ); } catch ( ArgumentException e ) { Console.WriteLine( e.ToString() ); }

Console.WriteLine();

// Searches the collection with Contains. Console.WriteLine( "Contains \"Three\": {0}", mySSC.Contains( "Three" ) ); Console.WriteLine( "Contains \"Twelve\": {0}", mySSC.Contains( "Twelve" ) ); Console.WriteLine();

// Removes an element from the collection. mySSC.Remove( "Two" );

// Displays the contents of the collection. Console.WriteLine( "After removing \"Two\":" ); PrintKeysAndValues1( mySSC );

}

// Uses the foreach statement which hides the complexity of the enumerator. // NOTE: The foreach statement is the preferred way of enumerating the contents of a collection. public static void PrintKeysAndValues1( ShortStringDictionary myCol ) { foreach ( DictionaryEntry myDE in myCol ) Console.WriteLine( " {0,-5} : {1}", myDE.Key, myDE.Value ); Console.WriteLine(); }

// Uses the enumerator. // NOTE: The foreach statement is the preferred way of enumerating the contents of a collection. public static void PrintKeysAndValues2( ShortStringDictionary myCol ) { DictionaryEntry myDE; System.Collections.IEnumerator myEnumerator = myCol.GetEnumerator(); while ( myEnumerator.MoveNext() ) if ( myEnumerator.Current != null ) { myDE = (DictionaryEntry) myEnumerator.Current;

Page 102: 70-536 test part 1

Console.WriteLine( " {0,-5} : {1}", myDE.Key, myDE.Value ); } Console.WriteLine(); }

// Uses the Keys property and the Item property. public static void PrintKeysAndValues3( ShortStringDictionary myCol ) { ICollection myKeys = myCol.Keys; foreach ( String k in myKeys ) Console.WriteLine( " {0,-5} : {1}", k, myCol[k] ); Console.WriteLine(); }

}

/* This code produces the following output.

Contents of the collection (using foreach): Three : abc Five : abcde Two : ab One : a Four : abcd

Contents of the collection (using enumerator): Three : abc Five : abcde Two : ab One : a Four : abcd

Initial contents of the collection (using Keys and Item): Three : abc Five : abcde Two : ab One : a Four : abcd

System.ArgumentException: value must be no more than 5 characters in length.Parameter name: value at ShortStringDictionary.OnValidate(Object key, Object value) at System.Collections.DictionaryBase.System.Collections.IDictionary.Add(Object key, Object value) at SamplesDictionaryBase.Main()System.ArgumentException: key must be no more than 5 characters in length.Parameter name: key at ShortStringDictionary.OnValidate(Object key, Object value)

Page 103: 70-536 test part 1

at System.Collections.DictionaryBase.System.Collections.IDictionary.Add(Object key, Object value) at SamplesDictionaryBase.Main()

Contains "Three": TrueContains "Twelve": False

After removing "Two": Three : abc Five : abcde One : a Four : abcd

*/