Prev | Current Page 284 | Next

Jon Skeet

"C# in Depth: What you need to master C# 2 and 3"


delegate Stream StreamFactory();
static MemoryStream GenerateRandomData()
{
byte[] buffer = new byte[16];
new Random().NextBytes(buffer);
return new MemoryStream(buffer);
}
...
StreamFactory factory = GenerateRandomData;
Stream stream = factory();
int data;
while ( (data=stream.ReadByte()) != -1)
{
Console.WriteLine(data);
}
The actual generation and display of the data in listing 5.3 is only present to give the code
something to do. (In particular, the way of generating random data is pretty awful!)
The important points are the annotated lines. We declare that the delegate type has a
return type of Stream B, but the GenerateRandomData method C has a return type of
MemoryStream. The line creating the delegate instance D performs the conversion we
saw earlier and uses covariance of return types to allow GenerateRandomData to be used
for the action for StreamFactory. By the time we invoke the delegate instance E, the
compiler no longer knows that a MemoryStream will be returned??”if we changed the type
of the stream variable to MemoryStream, we??™d get a compilation error.
Covariance and contravariance can also be used to construct one delegate instance
from another. For instance, consider these two lines of code (which assume an appropriate
HandleEvent method):
EventHandler general = new EventHandler(HandleEvent);
KeyPressEventHandler key = new KeyPressEventHandler(general);
The first line is valid in C# 1, but the second isn??™t??”in order to construct one delegate
from another in C# 1, the signatures of the two delegate types involved have to match.


Pages:
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296