Chapter 1. Type Fundamentals

This chapter explains the basics of creating types in C#. If you are already familiar with C#, much of this chapter will be a review for you.

After we cover class members such as fields, properties, and methods, you’ll learn about constructors, how to create and implement interfaces, and when to use structs.

The information in this chapter is basic, but vital. Like so many things, if you don’t get the fundamentals right, nothing else will work out.

Create a Class

Solution: Let’s begin by declaring a simple class that will hold 3D coordinate points.

image

The class we’ve defined is empty so far, but we’ll fill it up throughout this chapter.

The class is defined as public, which means it is visible to every other type that references its assembly. C# defines a number of accessibility modifiers, as detailed in Table 1.1.

Table 1.1 Accessibility Modifiers

image

If the class does not specify the accessibility, it defaults to internal.

Define Fields, Properties, and Methods

Solution: Let’s add some usefulness to the Vertex3d class.

image

Some notes on the preceding code:

• The fields are all declared private, which is good practice in general.

• The properties are declared public, but could also be private, protected, or protected internal, as desired.

• Properties can have get, set, or both.

• In properties, value is the implied argument (that is, in the code).

In the following example, 13.0 would be passed to X in the value argument:

Vertex3d v = new Vertex3d();
v.X = 13.0;

Use Auto-Implemented Properties

You will often see the following pattern:

image

C# has a shorthand syntax for this:

image

Note

You cannot have an auto-implemented property with only a get (if there’s no backing field, how would you set it?), but you can have a private set:

public int Field { get ; private set; }

Define Static Members

Solution: Add the modifying keyword static, as in the following method for adding two Vertex3d objects:

image

The static method is called like in this example:

image

Add a Constructor

Solution: Define a special method, called a constructor, with the same name as the class, with no return type. A constructor runs when a type is created—it is never called directly.

Here are two constructors for the Vertex3d class—one taking arguments, the other performing some default initialization.

image

Note

Constructors do not need to be public. For example, you could make a protected constructor that is only accessible from derived classes. You could even make a private constructor that prevents instantiation (for utility classes) or is accessible only from other methods in the same class (static factory methods, perhaps).

Add a Static Constructor and Initialization

Solution: Static fields can be initialized in two ways. One way is with a static constructor, which is similar to a standard constructor, but with no accessibility modifier or arguments:

image

However, because of performance reasons, it is preferable to initialize static fields inline whenever possible, as shown here:

image

Initialize Properties at Construction

Solution: Use object initialization syntax, as in the following example:

image

Use const and readonly

Solution: Both const and readonly are used to define data that does not change, but there are important differences: const fields must be defined at declaration. Because of this and the fact that they cannot change value, it implies that they belong to the type as static fields. On the other hand, readonly fields can be set at declaration or in the constructor, but nowhere else.

image

Reuse Code in Multiple Constructors

Solution: In C#, you are allowed to call other constructors within the same class using the this keyword, as shown next:

image

Derive from a Class

Solution: Use inheritance to reuse the base class and add new functionality.

image

Deriving from a class gives access to a base class’s public and protected members, but not private members.

Call a Base Class Constructor

Solution: Similar to calling other constructors from the constructor of a class, you can call specific constructors of a base class. If you do not specify a constructor, the base class’s default constructor is called. If the base class’s default constructor requires arguments, you will be required to supply them.

image

Override a Base Class’s Method or Property

Solution: The base class’s method or property must be declared virtual and must be accessible from the derived class. The derived class will use the override keyword.

image

Base class references can refer to instances of the base class or any class derived from it. For example, the following will print “28,” not “13.”

image

You can also call base class functions from a derived class via the base keyword.

image

Calling Derived.DoSomething will print out the following:

Base.DoSomething
Derived.DoSomething

Overriding Non-virtual Methods and Properties

Solution: You can still override it, but with a caveat: The override method will only be called through a reference to the derived class. To do this, use the new keyword (in a different context than you’re probably used to).

image

image

Here is the output of this code:

image

Make sure you understand why the output is the way it is.

Create an Interface

Solution: Here’s a sample interface for some kind of playable object—perhaps an audio or video file, or even a generic stream. An interface does not specify what something is, but rather some behavior.

image

Note that interfaces can contain methods as well as properties. (They can also contain events, which we will cover in Chapter 15, “Delegates, Events, and Anonymous Methods.”) You do not specify access with interfaces’ members because, by definition, they are all public.

Implement Interfaces

Solution: To implement an interface, you need to declare each interface method and property in your class, mark them public, and provide implementations.

image

Note

Visual Studio can help you out here. When you add “: IPlayable” after the class name, it will show a Smart Tag over it. Clicking the Smart Tag will give you the option to generate empty implementations of the interface in the class.

Implement Multiple Interfaces

Solution: A class can implement multiple interfaces, separated by commas:

image

However, you may run into instances where two (or more) interfaces define the same method. In our small example, suppose both IPlayable and IRecordable have a Stop() method defined. In this case, one interface must be made explicit.

image

Here is how to call these two methods:

image

Note that we arbitrarily decided that IRecordable’s Stop() method needed to be explicit—you could just have easily decided to make IPlayable’s Stop() method the explicit one.

Create a Struct

Unlike in C++, where structs and classes are functionally identical, in C#, there are important and fundamental differences:

• Structs are value types as opposed to reference types, meaning that they exist on the stack. They have less memory overhead and are appropriate for small data structures. They also do not have to be declared with the new operator.

• Structs cannot be derived from. They are inherently sealed (see Chapter 2, “Creating Versatile Types”).

• Structs may not have a parameterless constructor. This already exists implicitly and initializes all fields to zeros.

• All of a struct’s fields must be initialized in every constructor.

• Structs are passed by value, just like any other value-type, in method calls. Beware of large structs.

Solution: Defining a struct is similar to a class:

image

They can be used like so:

image

Create an Anonymous Type

Solution: The var keyword can be used to create anonymous types that contain properties you define inline.

image

This program produces the following output:

image

See Chapter 3, “General Coding,” for more information on how to use the var keyword.

Note

var might look like it’s untyped, but don’t be fooled. The compiler is generating a strongly typed object for you. Examine this code sample:

image

For that last line, the compiler will give this error:

Cannot implicitly convert type 'AnonymousType#2' to
'AnonymousType#1'

Prevent Instantiation with an Abstract Base Class

Solution: Mark your class as abstract.

image

You can also mark individual methods inside a class as abstract to avoid giving them any default implementation, as shown here:

image

Interface or Abstract Base Class?

When designing class hierarchies, you often need to decide whether classes at the root of the hierarchy (the parent classes) should be abstract base classes, or whether to implement the concrete classes in terms of interfaces.

Here are some guidelines to help make this decision.

In favor of interfaces:

• Will classes need to implement multiple base classes? This isn’t possible in C#, but it is possible to implement multiple interfaces.

• Have you separated concerns to the point where you understand the difference between what your class is and what it does? Interfaces are often about what the class does, whereas a base class can anchor what it is.

• Interfaces are often independent of what a class is and can be used in many situations. They can be added onto the class without concern for what it is.

• Interfaces often allow a very loosely coupled design.

• Deriving too many things from a base class can lead to it being bloated with too much functionality.

In favor of base classes:

• Is there reasonable common functionality or data for all derived types? An abstract base class may be useful.

• Implementing the same interface over many types can lead to a lot of repetition of code, whereas an abstract base class can group common code into a single implementation.

• An abstract base class can provide a default implementation.

• Abstract base classes tend to rigidly structure code. This may be desirable in some cases.

If you find yourself trying to put too much functionality into abstract base classes, another possibility is to look into componentizing the various areas of functionality.

As you gain experience, you’ll come to realize what makes sense in different situations. Often, some combination of the two makes sense.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset