Getting Started


Map<Key, Value> is likely the easiest BeanMap type to understand because by default it will behave identically to Dictionary.

var openPaths = new Map<string, string>();

openPaths["txt"] = "notepad";
openPaths["bmp"] = "mspaint";
openPaths["docx"] = "winword";

Assert.IsFalse(openPaths.ContainsKey("rtf"));

openPaths["rtf"] = "wordpad";

Assert.IsTrue(openPaths.ContainsKey("rtf"));

Assert.AreEqual("mspaint", openPaths["bmp"]);


Trying to use a nonexistent key will throw a KeyNotFoundException, as would be expected from Dictionary.


try
{
  var app = openPaths["unknown"];
}
catch (KeyNotFoundException ex)
{
}


But the power of Maps shines (even the one key map) when you need some custom behavior. All map types share some common properties.

DefaultValue

The default behavior is to throw a KeyNotFoundException, as Dictionary<> would. A default value is essentially an "error value". Common default values are null and 0. But the default value can be set to anything you need. When a default value is returned from a map, the requesting key+value pair is not stored.


var map = new Map<int, int>();
Assert.IsFalse(map.ContainsKey(1));

map[1] = 2;
Assert.AreEqual(2, map[1]);

map.DefaultValue = 0;
Assert.AreEqual(0, map[3]);
Assert.IsFalse(map.ContainsKey(3));

DefaultGeneration

DefaultGeneration is likely the most favored feature of BeanMap, at least in competition with the multiple-key feature of the other Map classes. DefaultGeneration is similar to DefaultValue in that it allows you specify the return value of nonexistent keys, except that DefaultGeneration will also create the requested key with that value.

Consider the following two code samples.


var _cache = new Map<long, AccountData>();

public void UseAccount(long accountId)
{
  if (!_cache.ContainsKey(accountId))
  {
    var data = LoadAccountDataExpensiveCall(accountId);
    _cache[accountId] = data;
  }

  UseAccountData(data);
}


Compare to:

var _cache = new Map<long, AccountData>() 
_cache.DefaultGeneration = accountId => LoadAccountDataExpensiveCall(accountId);

public void UseAccount(long accountId)
{
  UseAccountData(_cache[accountId];
}


The other (and perhaps even greater) benefit this example demonstrates is that the cache can also now be used anywhere in the code without the need of a wrapper method. You can just expect the cache to have the data because it will loaded when you first ask for it, without having to check if the key exists or not first.

KeyNotFoundBehavior

The map behavior is set to the last behavior specified. This is managed through the KeyNotFoundBehavior enum property on the Map class. The following lists the possible values and a description of the actions each behavior will take when a read is performed on a map key that does not exist.
  • ThrowKeyNotFoundException
    • throw a KeyNotFoundException. This is the default behavior intended to mimic Dictionary<>
  • DefaultGeneration
    • Execute the provided value-generation method and store the result in the map.
  • DefaultValue
    • Return the provided default value, and do not store the result.

Setting the DefaultValue or DefaultGeneration automatically modifies the KeyNotFoundBehavior for the given map. However, there is no property that will set the behavior back automatically to ThrowKeyNotFoundException. You can do that yourself by setting the KeyNotFoundBehvaior property manually. Note that directly setting the behavior to DefaultValue or DefaultGeneration without having given a value for either (in other words setting the behavior directly and not indirectly by setting DefaultValue or DefaultGeneration) will have undefined results (likely a null reference exception).


map.DefaultValue = -1;
Assert.AreEqual(-1, map[1]);

map.KeyNotFoundBehavior = KeyNotFoundBehavior.ThrowKeyNotFoundException;

try
{
  int i = map[1];
}
catch (KeyNotFoundException ex)
{
}

// bad idea, not intended use (do not do this!)
map.KeyNotFoundBehavior = KeyNotFoundBehavior.DefaultGeneration;

// undefined result (likely a null reference exception will be thrown
int v = map[4];


Last edited Feb 1, 2012 at 5:54 PM by payonel, version 5

Comments

No comments yet.