Chapter 3. General Coding

This chapter contains essential, general C# knowledge that doesn’t fit easily into other chapters: from the multitude of ways to declare variables to the different types of multidimensional arrays and some of the “unusual” operators in C#.

Declare Variables

Solution: C# provides many ways to declare and define variables. We’ll start with the simplest:

image

Use Type Inference (Implicit Typing)

Solution: Type inference allows you to let the compiler decide what type a local variable is (it cannot be used for class fields). It is important to realize that variables are still strongly typed—var is not equivalent to Object. You are merely giving the job of figuring out the type to the compiler. Once that’s done, the type can’t change during runtime.

image

This program produces the following output:

image

Apart from the benefit of convenience when typing (by omitting repeating type names), implicit typing is highly useful when using LINQ (see Chapter 21, “LINQ”).

Note

There is some amount of controversy about the usage of var. On one hand, it is mighty convenient when you don’t want to figure out and write out the type of an object you won’t be using outside of a narrow scope (especially when it’s long or has type parameters). On the other hand, it can definitely be overused.

My favorite place to use var is in foreach, so I don’t have to figure out what the precise type in the collection is, as in the following example:

image

Defer Type Checking to Runtime (Dynamic Types)

Solution: Use the dynamic keyword for your variables and method parameters.

This functionality is most useful in dynamic languages that require runtime binding, but it can be useful in other occasions. Here’s a simple demo:

image

image

For other examples, see the next section and in Chapter 24, “Reflection and Creating Plugins,” to see how dynamic typing can make method execution on reflected types easier.

Note

While the dynamic keyword gives us dynamic behavior, behind the scenes, the Dynamic Language Runtime (DLR) uses compiler tricks and reflection to bind the calls involving dynamic types to standard static types.

Use Dynamic Typing to Simplify COM Interop

Solution: Use dynamic typing to have the runtime do the checking and binding for you, as in the following example, which uses the Excel 2007 COM component.

image

Declare Arrays

Solution: There are many variations of array declaration and definition syntax.

image

Note

These additional ways of initializing an array actually apply to anything that implements IEnumerable (See Chapter 10, “Collections”, for examples of this). This is actually just another form of object initialization, which was described in Chapter 1, “Type Fundamentals.”

Create Multidimensional Arrays

Solution: First decide which type of multidimensional array you need. There are two types in C#: rectangular and jagged. The difference is illustrated in Figures 3.1 and 3.2.

Figure 3.1 Rectangular arrays have same-sized rows.

image

Figure 3.2 Jagged arrays are more like arrays of arrays.

image

Create Rectangular Arrays

Rectangular arrays are exactly what they sound like: every row is the same length. Here’s an example:

image

Create Jagged Arrays (Arrays of Arrays)

Jagged arrays are actually just arrays of arrays. Here’s an example:

image

Alias a Namespace

Solution: Rather than importing both types and thus polluting the current context (which would crowd IntelliSense, as one bad side effect), you can alias one or both of them into something shorter for easier use.

image

Note

The keyword using is also used in the context of the Dispose Pattern (see Chapter 22, “Memory Management”).

Use the Conditional Operator (?:)

Solution: Use the conditional operator, sometimes called the ternary operator (for its three arguments). For example, (condition?a:b) is shorthand for if (condition) { do a } else {do b}.

image

This program prints the following output:

x is 13
Condition is TRUE

Note

This operator is not limited to just assignments. You can also use it in situations like this:

bool actionSucceeded = CheckIfActionSucceeded();
actionSucceeded ? ReportSucceeded() : ReportFailed();

Use the Null-Coalescing Operator (??)

Solution: The null-coalescing operator can simplify the syntax a bit.

image

The output is as follows:

o = -1
obj2 = Hello

Add Methods to Existing Types with Extension Methods

Solution: Create an extension method using special syntax, as in this example:

image

image

A lot of extension methods are defined for you already (mostly for use in LINQ).

Figure 3.3 shows how Visual Studio marks extension methods graphically.

Figure 3.3 Visual Studio marks extension methods in IntelliSense with a down arrow to make them easy to identify. In this figure, Aggregate, All, Any, etc. are extension methods that operate on IEnumerable<T> types.

image

Note

Like operator overloading (See Chapter 2, “Creating Versatile Types”), you should be careful about defining extension methods because they pollute the namespace for all variables of that type.

Call Methods with Default Parameters

Solution: Use the new syntax in C# 4.0 to specify parameters with default values.

image

Note

Default parameter usage can be a contentious issue. Personally, I’d rather have more overloads than use default parameters, but the feature is now here if you want it. Make sure you don’t hurt readability and maintainability with its usage.

Call Methods with Named Parameters

Solution: Use the new syntax in C# 4.0 to call methods with named parameters.

Let’s use the same method from the previous section:

//order doesn't matter when they're named
ShowFolders(showFullPath: false, root: @"C:Windows");

Defer Evaluation of a Value Until Referenced

Solution: Use the simple helper class Lazy<T> to wrap the value creation and pass it around as needed. Once the value is created, it is stored so that subsequent accesses use the already created value.

image

image

The output is similar to the following:

image

Enforce Code Contracts

Solution: Use the Contract class to add constraints to your methods.

image

At first glance, these look like assertions—when you are running a debug build, they are. However, they do much more:

• When used with an external tool (called a binary rewriter), they inject code to verify the contract is obeyed, including possibly at the end of methods when needed.

• Emit metadata about the constraint that can then be analyzed by static code analysis tools.

• When run in debug mode, they throw exceptions when contracts are violated.

At the time of this writing, using Code Contracts required an extra download from Microsoft (go to http://research.microsoft.com/en-us/projects/contracts/). Once installed, Code Contracts will add a new tab in your project settings (see Figure 3.4).

Figure 3.4 Code Contracts adds some new configuration settings to Visual Studio.

image

With the Visual Studio Team System version, you can also have a static checker that evaluates your code as you write it and notifies you of problems immediately (see Figure 3.5).

Figure 3.5 The static checker integrates with Visual Studio Team System to interactively notify you of contract violations in your code.

image

Implement Contracts on Interfaces

Solution: Because interfaces don’t have method bodies, you need to create a surrogate implementation of the interface and add the contracts there. You tie them together using attributes.

image

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

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