You are on page 1of 4

Key: 5 Value: foo :

Key: 6 Value: foo :

((ArrayList) myMap[3])[0]: three


((ArrayList) myMap[3])[1]: duplicate three

myMap.Count: 6
entry.Key: 2 entry.Value(s): two :
entry.Key: 3 entry.Value(s): three : duplicate three : duplicate three :
entry.Key: 4 entry.Value(s):
entry.Key: 5 entry.Value(s): foo :
entry.Key: 6 entry.Value(s): foo :
entry.Key: 10 entry.Value(s): BAR : BAZ :

myMap.ContainsKey(2): True
myMap.ContainsValue(two): True
Contains Key 2: True
Contains Key 12: False
Contains Value two: True
Contains Value BAR: True

Discussion
A one-to-many map, or multimap, allows one object, a key, to be associated, or
mapped, to zero or more objects. The MultiMap<T,U> class presented here operates
similarly to a Dictionary<T,U>. The MultiMap<T,U> class contains a Dictionary<T,
List<U>> field called map that contains the actual mapping of keys to values. Several
of the MultiMap<T,U> methods are delegated to the methods on the map Dictionary<T,
List<U>> object.
A Dictionary<T,U> operates on a one-to-one principle: only one key may be associ-
ated with one value at any time. However, if you need to associate multiple values
with a single key, you must use the approach used by the MultiMap<T,U> class. The
private map field associates a key with a single List<U> of values, which allows multi-
ple mappings of values to a single key and mappings of a single value to multiple
keys. As an added feature, a key can also be mapped to a null value.
Here’s what happens when key-value pairs are added to a MultiMap<t,U> object:
1. The MultiMap<T,U>.Add method is called with a key and value provided as
parameters.
2. The Add method checks to see whether key exists in the map Dictionary<T,
List<U>> object.
3. If key does not exist, it is added as a key in the map Dictionary<T, List<U>>
object. This key is associated with a new List<U> as the value associated with key
in this Hashtable.
4. If the key does exist, the key is looked up in the map Dictionary<T, List<U>>
object, and the value is added to the key’s List<U>.

416 | Chapter 11: Data Structures and Algorithms


{
//throw (new Exception("Method1"));
//throw (new SecurityException("Method3"));
Console.WriteLine("Invoked Method3");
return 3;
}
}

It is also possible to decide whether to continue firing delegates in the list based on
the return value of the currently firing delegate. The following method fires each del-
egate, stopping only when a delegate returns a false value:
public static void InvokeWithTest( )
{
Func<bool> myDelegateInstanceBool1 = TestInvokeBoolReturn.Method1;
Func<bool> myDelegateInstanceBool2 = TestInvokeBoolReturn.Method2;
Func<bool> myDelegateInstanceBool3 = TestInvokeBoolReturn.Method3;

Func<bool> allInstancesBool =
myDelegateInstanceBool1 +
myDelegateInstanceBool2 +
myDelegateInstanceBool3;

Console.WriteLine(
"Invoke individually (Call based on previous return value):");
foreach (Func<bool> instance in allInstancesBool.GetInvocationList( ))
{
if (!instance( ))
break;
}
}

The following class contains each of the methods that will be called by the multicast
delegate allInstancesBool:
public class TestInvokeBoolReturn
{
public static bool Method1( )
{
Console.WriteLine("Invoked Method1");
return true;
}

public static bool Method2( )


{
Console.WriteLine("Invoked Method2");
return false;
}

public static bool Method3( )


{
Console.WriteLine("Invoked Method3");
return true;
}
}

Controlling When and If a Delegate Fires Within a Multicast Delegate | 321


Example 12-5. The CompressFile and DecompressFile methods (continued)
if (storedSize > fileLength ||
storedSize > workingSet)
throw new InvalidDataException( );

if (storedSize > chunkSize)


throw new InvalidDataException( );

byte[] uncompressedData = new byte[chunkSize];


byte[] compressedData = new byte[storedSize];
streamSource.Read(compressedData, 0,
compressedData.Length);

// uncompress the chunk


MemoryStream uncompressedDataStream =
new MemoryStream(compressedData);

if (compressionType == CompressionType.Deflate)
streamUncompressed =
new DeflateStream(uncompressedDataStream,
CompressionMode.Decompress);
else
streamUncompressed =
new GZipStream(uncompressedDataStream,
CompressionMode.Decompress);

using (streamUncompressed)
{
// read the chunk in the compressed stream
streamUncompressed.Read(uncompressedData, 0,
uncompressedData.Length);
}

// write out the uncompressed chunk


streamDestination.Write(uncompressedData, 0,
uncompressedData.Length);

// subtract the chunk size from the file size


fileLength -= chunkSize;

// if chunk is less than remaining file use remaining file


if (fileLength < chunkSize)
chunkSize = fileLength;
}
}
finally
{
streamSource.Close( );
streamDestination.Close( );
}
}

Compressing and Decompressing Your Files | 485


class or the static Move method of the Directory class instead. The static Move method
can be used to rename a directory in the following manner:
public static void RenameDirectory(string originalName, string newName)
{
try
{
// "rename" it
Directory.Move(originalName, newName);
}
catch(IOException ioe)
{
// most likely given the directory exists or isn't empty
Console.WriteLine(ioe.ToString( ));
}
}

This code creates a directory using the originalName parameter and renames it to the
value supplied in the newName parameter.
The instance MoveTo method of the DirectoryInfo class can also be used to rename a
directory via an extension method named Rename for DirectoryInfo shown here:
public static void Rename(this DirectoryInfo dirInfo, string newName)
{
try
{
// "rename" it
dirInfo.MoveTo(newName);
}
catch (IOException ioe)
{
// most likely given the directory exists or isn't empty
Trace.WriteLine(ioe.ToString( ));
}
}

This code creates a directory using the originalName parameter and renames it to the
value supplied in the newName parameter.

Discussion
The Move and MoveTo methods allow a directory to be moved to a different location.
However, when the path remains unchanged up to the directory that will have its
name changed, the Move methods act as Rename methods.

See Also
The “Directory Class” and “DirectoryInfo Class” topics in the MSDN
documentation.

458 | Chapter 12: Filesystem I/O

You might also like