Jeff Adkins' WebLog

Sr. Software Design Engineer, Microsoft

  • CSharpBits:The is and as Operators

    CSharp Bits is a tutorial-based digest that explains the C# programming language. It evolves, covering prerequisite topics and is currently broad in coverage rather than getting deep into a specific topic. That will come after a basis has been established.  I issue the topics daily (:p), and mainly cover one topic in each issue, so readers can fit it in their daily routine.  I email these topics internally at Microsoft and have been asked to blog the digests externally to reach out to the user community.

     All code examples are meant to demonstrate the topic only. It is neither shippable nor secure code by any stretch of the imagination.  An archive of the topics I submitted internally within Microsoft before I started blogging these out is not currently available externally.

    ==================================================================================================

    The is Operator

    You can handle incompatible types by catching InvalidCastException, but there are other ways of handling this problem, such as the is operator. The is operator allows you to determine whether an object reference can be converted into a reference to a given class.

    You can use the is operator to test the type of the object without performing a conversion. The is operator returns true if the value on the left is not null and a cast to the class on the right, if performed, would complete without throwing an exception. Otherwise, is returns false.

    if (a is Bird)
      
    b = (Bird) a; // Safe, because "a is Bird" returns true
    else
      
    Console.WriteLine("Not a Bird");

    You can think of the relationship between inherited classes as an "is a kind of" relationship, as in "A bird is a kind of animal." References in the variable a must be references to Animal objects, and b is a kind of animal. Of course, b is a bird as well, but a bird is just a special case of an animal. The converse is not true. An animal is not a type of bird. Some animals are birds, but it is not true that all animals are birds.

    So the following expression can be read as "If a is a kind of bird," or "If a is a bird or a type derived from bird."

    if (a is Bird)

     The as Operator

    You can use the as operator to perform conversions between types without raising an exception.

    The following statement performs a conversion of the reference in a to a value that references a class of type Bird, and the runtime automatically checks to ensure that the conversion is acceptable.

    b = a as Bird;

    Error Handling

    The as operator differs from the cast operator in the way it handles errors. If, in the preceding example, the reference in variable a cannot be converted in a reference to an object of class Bird, the value null is stored in b, and the program continues. The as operator never raises an exception.

    You can rewrite the previous code as follows to display an error message if the conversion cannot be performed:

    Bird b = a as Bird;
    if (b == null)
      
    Console.WriteLine("Not a bird");

    Although as never raises an exception, any attempt to access through the converted value will raise a NullReferenceException if it is null. Therefore, you should always check the return value from as.

  • CSharp Bits:Base/Derived Conversions

    CSharp Bits is a tutorial-based digest that explains the C# programming language. It evolves, covering prerequisite topics and is currently broad in coverage rather than getting deep into a specific topic. That will come after a basis has been established.  I issue the topics daily (:p), and mainly cover one topic in each issue, so readers can fit it in their daily routine.  I email these topics internally at Microsoft and have been asked to blog the digests externally to reach out to the user community.

     

    All code examples are meant to demonstrate the topic only. It is neither shippable nor secure code by any stretch of the imagination.  An archive of the topics I submitted internally within Microsoft before I started blogging these out is not currently available externally.

    ==

     

    Base/Derived Conversions

    You can convert a reference to an object of a derived class to an object of its base class, and vice versa, under certain conditions.

    Conversion to Base Class Reference

    References to objects of one class type can be converted into references to another type if one class inherits from the other, either directly or indirectly.

    A reference to an object can always be converted to a reference to a base class object. This conversion can be performed implicitly (by assignment or as part of an expression) or explicitly (by using the cast operator).

    The following examples will use two classes: Animal and Bird. Animal is the base class of Bird, or, to put it another way, Bird inherits from Animal.

    The following example declares a variable of type Animal and a variable of type Bird:

    Animal a;
    Bird b = new Bird(...);

    Now consider the following assignment, in which the reference in b is copied to a:

    a = b;

    The Bird class inherits from the Animal class. Therefore, a method that is found in Animal is also found in Bird. (The Bird class might have overridden some of the methods of Animal to create its own version of them, but an implementation of the method will exist nonetheless.) Therefore, it is possible for references to Bird objects to be assigned to variables containing references to objects of type Animal.

    In this case, C# performs a type conversion from Bird to Animal. You can explicitly convert Bird to Animal by using a cast operator, as shown:

    a = (Animal) b;

    The preceding code will produce exactly the same result.

    Conversion to Derived Class Reference

    You can convert a reference to a derived type, but you must explicitly specify the conversion by using a cast. An explicit conversion is subject to run-time checking to ensure that the types are compatible, as shown in the following example:

    Bird b = (Bird) a; // Okay

    This code will compile successfully. At run time, the cast operator performs a check to determine whether the object referred to is really of type Bird. If it is not, the run-time InvalidCastException is raised.

    If you attempt to assign to a derived type without a conversion operator, as in the following code, the compiler will display an error message stating, "Cannot implicitly convert type 'Animal' to 'Bird.'"

    b = a; // Will not compile

    You can trap a type conversion error by using try and catch, just like any other exception, as shown in the following code:

    try {
      
    b = (Bird) a;
    }
    catch (InvalidCastException) {
      
    Console.WriteLine("Not a bird");
    }

  • CSharpBits:Converting Value Types

    CSharp Bits is a tutorial-based digest explaining the C# programming language. It evolves, covering prerequisite topics and is currently broad in coverage rather than getting deep into a specific topic. That will come after a basis has been established.  It is an internal Microsoft distribution that I submit emails to on a daily basis (approximately).  The issues mainly cover one topic each, so readers can fit it in their daily routine.  I have been asked to blog the digests externally to reach out to the user community.

     

    All code examples are meant to demonstrate the topic only. It is neither shippable nor secure code by any stretch of the imagination.  An archive of previous topics is not currently available externally.

     

    Data Conversions

    In the upcoming issues, I will explain how to perform data conversions between reference types in C#. You can convert references from one type to another, but the reference types must be related.

    After reading the upcoming posts, you should be able to:

    ·           Identify permitted and prohibited conversions between reference types.

    ·           Use conversion mechanisms (casts, is, and as).

    ·           Identify special considerations for conversion to and from the object type.

    ·           Use the reflection mechanism, which allows examination of run-time type information.

    ·           Perform automatic conversions (boxing and unboxing) between value types and reference types.

    Converting Value Types

    C# supports implicit and explicit data conversions.

    Implicit Conversions

    For value types, I have previously described two ways to convert data: implicit conversion and explicit conversion using the cast operator.

    Implicit conversion occurs when a value of one type is assigned to another type. C# only allows implicit conversion for certain combinations of types, typically when the first value can be converted to the second without any data loss. The following example shows how data is converted implicitly from int to long:

    int a = 4;
    long b;
    b = a; // Implicit conversion of int to long

    Explicit Conversions

    You can explicitly convert value types by using the cast operator, as shown:

    int a;
    long b = 7;
    a = (int) b;

    Exceptions

    When you use the cast operator, you should be aware that problems might occur if the value cannot be held in the target variable. If a problem is detected during an explicit conversion (such as trying to fit the value 9,999,999,999 into an int variable), C# might raise an exception (in this case, the OverflowException). If you want, you can catch this exception by using try and catch, as shown:

    try {
       a = checked((int) b);
    }
    catch (Exception) {
       Console.WriteLine("Problem in cast");
    }

    For operations that involve integers, use the checked keyword or compile with the appropriate compiler settings, otherwise checking will not be performed.

    System.Convert Class

    Conversions between the different base types (such as int, long, and bool) are handled within the .NET Framework by the System.Convert class.

    You do not usually need to make calls to methods of System.Convert. The compiler handles these calls automatically.

  • CSharp Bits:System.IO Namespace

    Namespaces in the .NET Framework

    The .NET Framework provides common language services to a variety of application development tools. The classes in the framework provide an interface to the common language runtime, the operating system, and the network.

    System.IO Namespace

    The System.IO namespace is important because it contains many classes that allow an application to perform input and output (I/O) operations in various ways through the file system.

    The System.IO namespace also provides classes that allow an application to perform input and output operations on files and directories.

    The System.IO namespace is large and cannot be explained in detail here. However, the following list gives an indication of the facilities available:

    ·           The File and Directory classes allow an application to create, delete, and manipulate directories and files.

    ·           The StreamReader and StreamWriter classes enable a program to access file contents as a stream of bytes or characters.

    ·           The FileStream class can be used to provide random access to files.

    ·           The BinaryReader and BinaryWriter classes provide a way to read and write primitive data types as binary values.

    System.IO Example

    The following example shows how a file can be opened and read as a stream. The example is not meant to illustrate all of the possible ways in which the System.IO namespace can be used, but does show how you can perform a simple file copy operation.

    using System;
    using System.IO; // Use IO namespace
    // ...
    StreamReader reader = new StreamReader("infile.txt");
    // Text in from file
    StreamWriter writer = new StreamWriter("outfile.txt");
    // Text out to file
    string line;
    while ((line = reader.ReadLine( )) != null)
    {
       writer.WriteLine(line);
    }

    reader.Close( );
    writer.Close( );

    To open a file for reading, the code in the example creates a new StreamReader object and passes the name of the file that needs to be opened in the constructor. Similarly, to open a file for writing, the example creates a new StreamWriter object and passes the output file name in its constructor. In the example, the file names are hard-coded, but they could also be string variables.

    The example program copies a file by reading one line at a time from the input stream and writing that line to the output stream.

    ReadLine and WriteLine might look familiar. The Console class has two static methods of that name. In the example, the methods are instance methods of the StreamReader and StreamWriter classes, respectively.

    For more information about the System.IO namespace, search for "System.IO namespace" in the .NET Framework SDK Help documents.

  • CSharpBits:Reflection

    Reflection

    You can obtain information about the type of an object by using a mechanism called reflection.

    The reflection mechanism in C# is handled by the System.Reflection namespace in the .NET Framework. This namespace contains classes and interfaces that provide a view of types, methods, and fields.

    The System.Type class provides methods for obtaining information about a type declaration, such as the constructors, methods, fields, properties, and events of a class. A Type object that represents a type is unique; that is, two Type object references refer to the same object only if they represent the same type. This allows comparison of Type objects through reference comparisons (the == and != operators).

    The typeof Operator

    At compile time, you can use the typeof operator to return the type information from a given type name.

    The following example retrieves run-time type information for the type byte, and displays the type name to the console.

    using System;
    using System.Reflection;
    Type t = typeof(byte);
    Console.WriteLine("Type: {0}", t);

    The following example displays more detailed information about a class. Specifically, it lists the methods for that class.

    using System;
    using System.Reflection;
    Type t = typeof(string); // Get type information
    MethodInfo[ ] mi = t.GetMethods( );
    foreach (MethodInfo m in mi) {
      
    Console.WriteLine("Method: {0}", m);
    }

    GetType Method

    The typeof operator only works on classes that exist at compile time. If you need type information at run time, you can use the GetType method of the Object class.

  • CSharp Bits:Common Methods for All Reference Types

    I was asked to externally blog my posts to an internal Microsoft email distribution group that I own called CSharp Bits.  This digest is comprised of C# topics that I try to issue daily, typically one topic per post.  It is a tutorial approach so prerequisites are covered.  I have an archive of topics leading up to this one, but I 'm not sure if I will blog those.  I am currently covering how to use reference types in C#.  In this inaugural blog, I pick up at the topic of "Common Methods for All Reference Types"...

     

    Common Methods for All Reference Types

    The object type provides a number of common methods. Because every type inherits from object, the derived types have these methods too. These common methods include the following:

    ·                  ToString

    ·                  Equals

    ·                  GetType

    ·                  Finalize

    ToString Method

    The ToString method returns a string that represents the current object.

    The default implementation, as found in the Object class, returns the type name of the class. The following example uses the coordinate example class defined earlier:

    coordinate c = new coordinate( );
    Console.WriteLine(c.ToString( ));

    This example will display "coordinate" on the console.

    However, you can override the ToString method in class coordinate to render objects of that type into something more meaningful, such as a string containing the values held in the object.

    Equals Method

    The Equals method determines whether the specified object is the same instance as the current object. The default implementation of Equals supports reference equality only, as you have already seen.

    Subclasses can override this method to support value equality instead.

    GetType Method

    This method allows extraction of run-time type information from an object. I will discuss this in more detail in the Data Conversions section in a later topic.

    Finalize Method

    This method is called by the run-time system when an object becomes inaccessible.


© 2009 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Microsoft
Page view tracker