181Summary
(without using a dedicated thread) until it had completed, calling the supplied dele-
gate to handle the result. It would then call
MoveNext
again, and our method would
continue. This time we kick off two requests in parallel, and the
CCR to call another del-
egate with the results of both operations when they’ve both finished. After that,
Move-
Next
is called for a final time and we get to complete the request processing.
Although it’s obviously more complicated than the synchronous version, it’s still all
in one method, it will get executed in the order written, and the method itself can
hold the state (in the local variables, which become state in the extra type generated
by the compiler). It’s fully asynchronous, using as few threads as it can get away with. I
haven’t shown any error handling, but that’s also available in a sensible fashion that
forces you to think about the issue at appropriate places.
It all takes a while to get your head around (at least unless you’ve seen continuation-
passing style code before) but the potential benefits in terms of writing correct, scalable
code are enormous—and it’s only feasible in such a neat way due to C#
2’s syntactic
sugar around iterators and anonymous methods. The
CCR hasn’t hit the mainstream at
the time of writing, but it’s possible that it will become another normal part of the
development toolkit
11
—and that other novel uses for iterator blocks will be thought up
over time. As I said earlier, the point of the section is to open your mind to possible uses
of the work that the compiler can do for you beyond just simple iteration.
6.5 Summary
C# supports many patterns indirectly, in terms of it being feasible to implement them
chapter 13.
182 CHAPTER 6 Implementing iterators the easy way
before—in computer science the term coroutine is applied to concepts of this nature.
Different languages have historically supported them to a greater or lesser extent,
with tricks being applicable to simulate them sometimes—for example, Simon
Tatham has an excellent article
12
on how even C can express coroutines if you’re will-
ing to bend coding standards somewhat. We’ve seen that C#
2 makes coroutines easy
to write and use.
Having seen some major and sometimes mind-warping language changes focused
around a few key features, our next chapter is a change of pace. It describes a number
of small changes that make C#
2 more pleasant to work with than its predecessor,
learning from the little niggles of the past to produce a language that has fewer rough
edges, more scope for dealing with awkward backward-compatibility cases, and a bet-
ter story around working with generated code. Each feature is relatively straightfor-
ward, but there are quite a few of them…
12
/>183
Concluding C# 2:
the final features
So far we’ve looked at the four biggest new features of C# 2: generics, nullable types,
delegate enhancements, and iterator blocks. Each of these addresses a fairly complex
requirement, which is why we’ve gone into each of them in some depth. The remain-
ing new features of C#
2 are knocking a few rough edges off C# 1. They’re little niggles
that the language designers decided to correct—either areas where the language
Partial types—The ability to write the code for a type in multiple source files;
particularly handy for types where part of the code is autogenerated and the
rest is written manually.
■
Static classes—Tidying up utility classes so that the compiler can make it clearer
when you’re trying to use them inappropriately.
■
Separate getter/setter property access—Finally, the ability to have a public getter and
a private setter for properties! (That’s not the only combination available, but
it’s the most common one.)
■
Namespace aliases—Ways out of sticky situations where type names aren’t unique.
■
Pragma directives—Compiler-specific instructions for actions such as suppressing
specific warnings for a particular section of code.
■
Fixed-size buffers—More control over how structs handle arrays in unsafe code.
■
InternalsVisibleToAttribute (friend assemblies)—A feature spanning library, frame-
work, and runtime, this allows selected assemblies more access when required.
You may well be itching to get on to the sexy stuff from C#
3 by this point, and I don’t
blame you. Nothing in this chapter is going to set the world on fire—but each of these
features can make your life more pleasant, or dig you out of a hole in some cases. Hav-
ing dampened your expectations somewhat, our first feature is actually pretty nifty.
7.1 Partial types
The first change we’ll look at is due to the power struggle that was usually involved
when using code generators with C#
1. For Windows Forms, the designer in Visual Stu-
dio had to have its own regions of code that couldn’t be touched by developers, within
figure 7.1—there’s no need for “forward references” or other tricks.
You can’t write half of a member in one file and half of it in another—each individ-
ual member has to be complete within its own file.
1
There are a few obvious restric-
tions about the declarations of the type—the declarations have to be compatible. Any
file can specify interfaces to be implemented (and they don’t have to be implemented
in that file); any file can specify the base type; any file can specify a type parameter
constraint. However, if multiple files specify a base type, those base types have to be
the same, and if multiple files specify type parameter constraints, the constraints have
to be identical. Listing 7.1 gives an example of the flexibility afforded (while not
doing anything even remotely useful).
1
There’s an exception here: partial types can contain nested partial types spread across the same set of files.
partial class Example
{
void FirstMethod()
{
SecondMethod();
}
void ThirdMethod()
{
}
}
partial class Example
{
void SecondMethod()
{
ThirdMethod();
}
D
) contribute to the list of interfaces that must
be implemented. In this example, each file implements the interfaces it declares,
and that’s a common scenario, but it would be legal to move the implementation of
IDisposable
E
to Example1.cs and the implementation of
IEquatable<string>
C
to Example2.cs. Only
B
specified any type constraints, and only
C
specified a base
class. If
B
specified a base class, it would have to be
EventArgs
, and if
D
specified
any type constraints they’d have to be exactly as in
B
. In particular, we couldn’t spec-
ify a type constraint for
TSecond
in
D
class and interface
D
E
Implements
IDisposable
187Partial types
code generator can own the file where it will work, and completely overwrite the
whole file every time it wants to.
Some code generators may even choose not to generate a C# file at all until the
build is well under way. For instance, the Windows Presentation Foundation version of
the Snippy application has Extensible Application Markup Language (
XAML) files
that describe the user interface. When the project is built, each
XAML file is converted
into a C# file in the obj directory (the filenames end with “.g.cs” to show they’ve been
generated) and compiled along with the partial class providing extra code for that
type (typically event handlers and extra construction code). This completely prevents
developers from tweaking the generated code, at least without going to extreme
lengths of hacking the build file.
I’ve been careful to use the phrase code generator instead of just designer because
there are plenty of code generators around besides designers. For instance, in Visual
Studio 2005 web service proxies are generated as partial classes, and you may well
have your own tools that generate code based on other data sources. One reasonably
common example of this is Object Relational Mapping (
ORM)—some ORM tools use
database entity descriptions from a configuration file (or straight from the database)
and generate partial classes representing those entities.
This makes it very straightforward to add behavior to the type: overriding virtual
methods of the base class, adding new members with business logic, and so forth. It’s a
great way of letting the developer and the tool work together, rather than constantly
2 features—but partial methods don’t fit with any of the
other C#
3 features and they do fit in very well when describing partial types. Apologies
for any confusion this may cause.
Back to the feature: sometimes we want to be able to specify behavior in a manually
created file and use that behavior from an automatically generated file. For instance,
in a class that has lots of automatically generated properties, we might want to be able
to specify code to be executed as validation of a new value for some of those proper-
ties. Another common scenario is for a code-generation tool to include construc-
tors—manually written code often wants to hook into object construction to set
default values, perform some logging, and so forth.
In C#
2, these requirements could only be met either by using events that the man-
ually generated code could subscribe to, or by making the automatically generated
code assume that the handwritten code will include methods of a particular name—
making the whole code fail to compile unless the relevant methods are provided.
Alternatively, the generated code can provide a base class with virtual methods that do
nothing by default. The manually generated code can then derive from the class and
override some or all of the methods.
All of these solutions are somewhat messy. C#
3’s partial methods effectively pro-
vide optional hooks that have no cost whatsoever if they’re not implemented—any calls
to the unimplemented partial methods are removed by the compiler. It’s easiest to
understand this with an example. Listing 7.2 shows a partial type specified in two files,
with the constructor in the automatically generated code calling two partial methods,
one of which is implemented in the manually generated code.
GuiPage.xaml.cs
(Handwritten C#)
GuiPage.xaml
(XAML)
Console.WriteLine("Generated constructor");
OnConstructorEnd();
}
partial void OnConstructorStart();
partial void OnConstructorEnd();
}
// Handwritten.cs
using System;
partial class PartialMethodDemo
{
partial void OnConstructorEnd()
{
Console.WriteLine("Manual code");
}
}
As shown in listing 7.2, partial methods are declared just like abstract methods: by pro-
viding the signature without any implementation but using the
partial
modifier.
Similarly, the actual implementations just have the
partial
modifier but are other-
wise like normal methods.
Calling the parameterless constructor of
PartialMethodDemo
would result in “Gen-
erated constructor” and then “Manual code” being printed out. Examining the
IL for
the constructor, you wouldn’t see a call to
OnConstructorStart
be implementing partial methods than declaring and calling them. If you’re only imple-
menting them, you don’t need to worry about the argument evaluation side of things.
In summary, partial methods in C#
3 allow generated code to interact with handwrit-
ten code in a rich manner without any performance penalties for situations where the
interaction is unnecessary. This is a natural continuation of the C#
2 partial types fea-
ture, which enables a much more productive relationship between code-generation
tools and developers.
Our next feature is entirely different, and is just a way of telling the compiler more
about the intended nature of a type so that it can perform more checking on both the
type itself and any code using it.
7.2 Static classes
Our second new feature is in some ways completely unnecessary—it just makes things
tidier and a bit more elegant when you write utility classes.
Everyone has utility classes. I haven’t seen a significant project in either Java or C#
that didn’t have at least one class consisting solely of static methods. The classic exam-
ple appearing in developer code is a type with string helper methods, doing anything
from escaping, reversing, smart replacing—you name it. An example from the Frame-
work is the
System.Math
class. The key features of a utility class are as follows:
■
All members are static (except a private constructor).
■
The class derives directly from
object
.
■
Typically there’s no state at all, unless there’s some caching or a singleton
}
The private constructor
B
may seem odd—why have it at all if it’s private and never
going to be used? The reason is that if you don’t supply any constructors for a class, the
C#
1 compiler will always provide a default constructor that is public and parameterless. In
this case, we don’t want any visible constructors, so we have to provide a private one.
This pattern works reasonably well, but C#
2 makes it explicit and actively prevents
the type from being misused. First we’ll see what changes are needed to turn listing 7.3
into a “proper” static class as defined in C#
2. As you can see from listing 7.4, very little
action is required.
using System;
public static class StringHelper
{
public static string Reverse(string input)
{
char[] chars = input.ToCharArray();
Array.Reverse(chars);
return new string(chars);
}
}
We’ve used the
static
modifier in the class declaration this time instead of
sealed
,
and we haven’t included a constructor at all—those are the only code differences. The
The compiler not only puts constraints on the definition of static classes, though—
it also guards against their misuse. As it knows that there can never be any instances of
Listing 7.4 The same utility class as in listing 7.3 but converted into a C# 2 static class
All methods
are static
192 CHAPTER 7 Concluding C# 2: the final features
the class, it prevents any use of it that would require one. For instance, all of the fol-
lowing are invalid when
StringHelper
is a static class:
StringHelper variable = null;
StringHelper[] array = null;
public void Method1(StringHelper x) {}
public StringHelper Method1() { return null; }
List<StringHelper> x = new List<StringHelper>();
None of these are prevented if the class just follows the C# 1 pattern—but all of them
are essentially useless. In short, static classes in C#
2 don’t allow you to do anything you
couldn’t do before—but they prevent you from doing things that you shouldn’t have
been doing anyway.
The next feature on our list is one with a more positive feel. It’s aimed at a very spe-
cific—although widely encountered—situation, and allows a solution that is neither
ugly nor breaks encapsulation, which was the choice available in C#
1.
7.3 Separate getter/setter property access
I’ll admit to being slightly bemused when I first saw that C# 1 didn’t allow you to have
a public getter and a private setter for properties. This isn’t the only combination of
access modifiers that is prohibited by C#
1, but it’s the most commonly desired one. In
fact, in C#
but we can
use the familiar property syntax for setting the property within the type itself. The
2
Except nested types, which always have access to private members of their enclosing types.
193Namespace aliases
same syntax is also available for indexers as well as properties. You could make the set-
ter more public than the getter (a protected getter and a public setter, for example)
but that’s a pretty rare situation, in the same way that write-only properties are few and
far between compared with read-only properties.
NOTE Trivia: The only place where “private” is required—Everywhere else in C#, the
default access modifier in any given situation is the most private one pos-
sible. In other words, if something can be declared to be private, then leav-
ing out the access modifiers entirely will default it to being private. This is
a nice element of language design, because it’s hard to get it wrong acci-
dentally: if you want something to be more public than it is, you’ll notice
when you try to use it. If, however, you accidentally make something “too
public,” then the compiler can’t help you to spot the problem. For this rea-
son, my personal convention is not to use any access modifiers unless I
need to; that way, the code highlights (by way of an access modifier) when
I’ve explicitly chosen to make something more public than it might be.
Specifying the access of a property getter or setter is the one exception to
this rule—if you don’t specify anything, the default is to give the getter/
setter the same access as the overall property itself.
Note that you can’t declare the property itself to be private and make the getter pub-
lic—you can only make a particular getter/setter more private than the property. Also,
you can’t specify an access modifier for both the getter and the setter—that would just
be silly, as you could declare the property itself to be whichever is the more public of
the two modifiers.
This aid to encapsulation is long overdue. There’s still nothing in C#
2 to stop
Dispose
automatically) was available in two flavors—one created an alias for a
194 CHAPTER 7 Concluding C# 2: the final features
namespace or type (for example,
using
Out
=
System.Console;
) and the other just
introduced a namespace into the list of contexts the compiler would search when
looking for a type (for example,
using
System.IO;
). By and large, this was adequate,
but there are a few situations that the language simply couldn’t cope with, and others
where automatically generated code would have to go out of its way to make abso-
lutely sure that the right namespaces and types were being used whatever happened.
C#
2 fixes these problems, bringing an additional robustness to the language. It’s
not that the code being generated is any more robust in terms of execution, but you
can write code that is guaranteed to mean what you want it to regardless of which
other types, assemblies, and namespaces are introduced. These extreme measures are
rarely needed outside automatically generated code, but it’s nice to know that they’re
there when you need them. In C#
2 there are three types of aliases: the namespace
aliases of C#
a problem, however—what if someone were to introduce a type or namespace called
WinForms
or
WebForms
? The compiler wouldn’t know what
WinForms.Button
meant,
and would use the type or namespace in preference to the alias. We want to be able to
tell the compiler that we need it to treat
WinForms
as an alias, even though it’s avail-
able elsewhere. C#
2 introduces the
::
syntax to do this, as shown in listing 7.6.
Listing 7.5 Using aliases to distinguish between different Button types
195Namespace aliases
using System;
using WinForms = System.Windows.Forms;
using WebForms = System.Web.UI.WebControls;
class WinForms
{
}
class Test
{
static void Main()
{
Console.WriteLine (typeof (WinForms::Button));
Console.WriteLine (typeof (WebForms::Button));
}
In C#
1, there was simply no way of getting around this. Again, C# 2 comes to the
rescue, allowing you to use
global::Configuration
to tell the compiler exactly what
you want. Listing 7.7 demonstrates both the problem and the solution.
using System;
class Configuration {}
namespace Chapter7
{
class Configuration {}
class Test
{
static void Main()
{
Console.WriteLine(typeof(Configuration));
Console.WriteLine(typeof(global::Configuration));
Console.WriteLine(typeof(global::Chapter7.Test));
}
}
}
Listing 7.6 Using :: to tell the compiler to use aliases
Listing 7.7 Use of the global namespace alias to specify the desired type exactly
196 CHAPTER 7 Concluding C# 2: the final features
Most of listing 7.7 is just setting up the situation—the three lines within
Main
are the
interesting ones. The first line prints “Chapter7.Configuration” as the compiler
resolves
Configuration
name to distinguish them, as they’ve both got the same fully qualified name. Instead, we
can use extern aliases to specify which we mean. Listing 7.8 shows an example of the C#
code involved, along with the command line needed to compile it.
// Compile with
// csc Test.cs /r:FirstAlias=First.dll /r:SecondAlias=Second.dll
extern alias FirstAlias;
extern alias SecondAlias;
using System;
using FD = FirstAlias::Demo;
class Test
{
static void Main()
{
Console.WriteLine(typeof(FD.Example));
Listing 7.8 Working with different types of the same type in different assemblies
Specifies two
extern aliases
B
Refers to extern alias
with namespace alias
Uses
namespace
alias
C
197Pragma directives
Console.WriteLine(typeof(SecondAlias::Demo.Example));
Console.ReadLine();
}
}
The code in listing 7.8 is quite straightforward, and demonstrates that you can
Our next feature is almost a meta-feature. The
exact purpose it serves depends on which com-
piler you’re using, because its whole purpose is to
enable control over compiler-specific features—
but we’ll concentrate on the Microsoft compiler.
7.5 Pragma directives
Describing pragma directives in general is extremely easy: a pragma directive is a pre-
processing directive represented by a line beginning with
#pragma
. The rest of the line
can contain any text at all. The result of a pragma directive cannot change the behav-
ior of the program to contravene anything within the C# language specification, but it
can do anything outside the scope of the specification. If the compiler doesn’t under-
stand a particular pragma directive, it can issue a warning but not an error.
That’s basically everything the specification has to say on the subject. The
Microsoft C# compiler understands two pragma directives: warnings and checksums.
7.5.1 Warning pragmas
Just occasionally, the C# compiler issues warnings that are justifiable but annoying.
The correct response to a compiler warning is almost always to fix it—the code is rarely
made worse by fixing the warning, and usually it’s improved.
However, just occasionally there’s a good reason to ignore a warning—and that’s
what warning pragmas are available for. As an example, we’ll create a private field that
D
Uses
extern alias
directly
Figure 7.3 Part of the Properties
window of Visual Studio 2008,
showing an extern alias of FirstAlias
for the First.dll reference
idea in almost every imaginable scenario.
7.5.2 Checksum pragmas
You’re very unlikely to need the second form of pragma recognized by the Microsoft
compiler. It supports the debugger by allowing it to check that it’s found the right
source file. Normally when a C# file is compiled, the compiler generates a checksum
from the file and includes it in the debugging information. When the debugger needs
to locate a source file and finds multiple potential matches, it can generate the check-
sum itself for each of the candidate files and see which is correct.
Now, when an
ASP.NET page is converted into C#, the generated file is what the C#
compiler sees. The generator calculates the checksum of the .aspx page, and uses a
Listing 7.9 Class containing an unused field
Listing 7.10 Disabling (and restoring) warning CS0169
199Fixed-size buffers in unsafe code
checksum pragma to tell the C# compiler to use that checksum instead of calculating
one from the generated page.
The syntax of the checksum pragma is
#pragma checksum "filename" "{guid}" "checksum bytes"
The GUID indicates which hashing algorithm has been used to calculate the check-
sum. The documentation for the
CodeChecksumPragma
class gives GUIDs for SHA-1 and
MD5, should you ever wish to implement your own dynamic compilation framework
with debugger support.
It’s possible that future versions of the C# compiler will include more pragma
directives, and other compilers (such as the Mono compiler, mcs) could have their
own support for different features. Consult your compiler documentation for the
most up-to-date information.
The next feature is another one that you may well never use—but at the same time,
if you ever do, it’s likely to make your life somewhat simpler.
There are remarkably few Windows
APIs where this feature is directly useful. There
are numerous situations where a fixed array of characters is called for—the
TIME_
ZONE_INFORMATION
structure, for example—but unfortunately fixed-size buffers of char-
acters appear to be handled poorly by
P/Invoke, with the marshaler getting in the way.
200 CHAPTER 7 Concluding C# 2: the final features
As one example, however, listing 7.11 is a console application that displays the colors
available in the current console window. It uses an
API function
GetConsoleScreen-
BufferEx
that is new to Vista and Windows Server 2008, and that retrieves extended con-
sole information. Listing 7.11 displays all 16 colors in hexadecimal format (
bbggrr
).
using System;
using System.Runtime.InteropServices;
struct COORD
{
public short X, Y;
}
struct SMALL_RECT
{
public short Left, Top, Right, Bottom;
}
unsafe struct CONSOLE_SCREEN_BUFFER_INFOEX
{
Listing 7.11 Demonstration of fixed-size buffers to obtain console color information
201Exposing internal members to selected assemblies
Listing 7.11 uses fixed-size buffers for the table of colors. Before fixed-size buffers, we
could still have used the
API either with a field for each color table entry or by mar-
shaling a normal array as
UnmanagedType.ByValArray
. However, this would have cre-
ated a separate array on the heap instead of keeping the information all within the
structure. That’s not a problem here, but in some high-performance situations it’s
nice to be able to keep “lumps” of data together. On a different performance note, if
the buffer is part of a data structure on the managed heap, you have to pin it before
accessing it. If you do this a lot, it can significantly affect the garbage collector. Stack-
based structures don’t have this problem, of course.
I’m not going to claim that fixed-size buffers are a hugely important feature in
C#
2—at least, they’re not important to most people. I’ve included them for com-
pleteness, however, and doubtless someone, somewhere will find them invaluable.
Our final feature can barely be called a C#
2 language feature at all—but it just about
counts, so I’ve included it for completeness.
7.7 Exposing internal members to selected assemblies
There are some features that are obviously in the language—iterator blocks, for exam-
ple. There are some features that obviously belong to the runtime, such as
JIT com-
piler optimizations. There are some that clearly sit in both camps, like generics. This
last feature has a toe in each but is sufficiently odd that it doesn’t merit a mention in
either specification. In addition, it uses a term that has different meanings in C++ and
VB.NET—adding a third meaning to the mix. To be fair, all the terms are used in the
context of access permissions, but they have different effects.
using System.Runtime.CompilerServices;
[assembly:InternalsVisibleTo("FriendAssembly")]
public class Source
{
internal static void InternalMethod()
{
}
public static void PublicMethod()
{
}
}
// Compiled to FriendAssembly.dll
public class Friend
{
static void Main()
{
Source.InternalMethod();
Source.PublicMethod();
}
}
// Compiled to EnemyAssembly.dll
public class Enemy
{
static void Main()
{
// Source.InternalMethod();
Source.PublicMethod();
}
}
Uses additional
access within
FriendAssembly
EnemyAssembly has
no special access
B
Accesses public
method as normal
203Exposing internal members to selected assemblies
making members internal for the sake of testing where they might otherwise be private,
but that’s a less worrying step.)
The only downside to this is that the name of your test assembly lives on in your
production assembly. In theory this could represent a security attack vector if your
assemblies aren’t signed, and if your code normally operates under a restricted set of
permissions. (Anyone with full trust could use reflection to access the members in the
first place. You could do that yourself for unit tests, but it’s much nastier.) If this ever
ends up as a genuine issue for anyone, I’ll be very surprised. It does, however, bring
the option of signing assemblies into the picture. Just when you thought this was a
nice, simple little feature…
7.7.3 InternalsVisibleTo and signed assemblies
If a friend assembly is signed, the source assembly needs to specify the public key of the
friend assembly, to make sure it’s trusting the right code. Contrary to a lot of documen-
tation, it isn’t the public key token that is required but the public key itself. For instance,
consider the following command line and output (rewrapped and modified slightly for
formatting) used to discover the public key of a signed
FriendAssembly.dll
:
c:\Users\Jon\Test>sn -Tp FriendAssembly.dll
Microsoft (R) .NET Framework Strong Name Utility Version 3.5.21022.8
Copyright (c) Microsoft Corporation. All rights reserved.
assembly, so typically you end up with both assemblies being signed if either one of
them is.
7.8 Summary
This completes our tour of the new features in C# 2. The topics we’ve looked at in this
chapter have broadly fallen into two categories: “nice to have” improvements that
streamline development, and “hope you don’t need it” features that can get you out of
tricky situations when you need them. To make an analogy between C#
2 and improve-
ments to a house, the major features from our earlier chapters are comparable to full-
scale additions. Some of the features we’ve seen in this chapter (such as partial types
and static classes) are more like redecorating a bedroom, and features like namespace
aliases are akin to fitting smoke alarms—you may never see a benefit, but it’s nice to
know they’re there if you ever need them.
The range of features in C#
2 is very broad—the designers tackled many of the
areas where developers were feeling pain, without any one overarching goal. That’s
not to say the features don’t work well together—nullable value types wouldn’t be fea-
sible without generics, for instance—but there’s no one aim that every feature contrib-
utes to, unless you count general productivity.
Now that we’ve finished examining C#
2, it’s time to move on to C# 3, where the
picture is very different. Nearly every feature in C#
3 (with the exception of partial
methods, which we’ve covered in this chapter) forms part of the grand picture of
LINQ, a conglomeration of technologies that could well change the way traditional
programmers think—forever.
Part 3
C# 3—
revolutionizing