I posted this class definition on another thread and decided that it would be a good idea to post it in the Code Library as well. It is a generic, global object caching class, working in a dictionary-like manner (and, in fact, backed by a Dictionary<string, TValue> object).
Because of the way that .Net handles fields of static classes you are provided a complete and separate cache for each type. (Or, to be more accurate, for each type parameter. For example, you can store a Bitmap in Cache<Image> and it will not be found in Cache<Bitmap>. Likewise, a Bitmap stored in Cache<Bitmap> will not be found in Cache<Image>.) The Cache class provides indexers and enumerators, and is implemented in a manner that makes the use of keys to identify objects completely optional.
The Cache<T> class generally performs the same function that a statically declared Dictionary<TKey, TValue> object would, but it can be more convinient to write code with, and, again, the use of keys is optional.
Unfortunately, because of a technical issue (overloading), Cache<string> will be difficult if not impossible to use.
Here is an example of using the Cache<T> class.
Because of the way that .Net handles fields of static classes you are provided a complete and separate cache for each type. (Or, to be more accurate, for each type parameter. For example, you can store a Bitmap in Cache<Image> and it will not be found in Cache<Bitmap>. Likewise, a Bitmap stored in Cache<Bitmap> will not be found in Cache<Image>.) The Cache class provides indexers and enumerators, and is implemented in a manner that makes the use of keys to identify objects completely optional.
C#:
static class Cache<T>
{
// Backing collection
static Dictionary<string, T> values;
static Cache() {
// Create a dicationary with case-insensitive strings for keys.
values = new Dictionary<string, T>(StringComparer.InvariantCultureIgnoreCase);
}
public static T GetItem(string key){
return values[key];
}
#region Add/Remove methods
/// <summary>
/// Adds an object with a specified key to the cache.
/// </summary>
/// <param name="key">The key under which the object is stored.</param>
/// <param name="value">The object to store.</param>
public static void Add(string key, T value){
values.Add(key, value);
}
/// <summary>
/// Adds an object to the cache, generating a key automatically.
/// </summary>
/// <param name="value">The value to store.</param>
public static void Add(T value){
values.Add(
//Create a key based on the object's hash code, ideally
//ensuring that unique objects obtain unique keys.
value.GetHashCode().ToString(),
value);
}
/// <summary>
/// Removes an object from the cache by specifying the key.
/// </summary>
/// <param name="key">The key of the object to remove from the cache.</param>
/// <returns>A value indicating success or failure of the operation.</returns>
public static bool Remove(string key) {
return values.Remove(key);
}
/// <summary>
/// Removes an object from the cache by specifying the key.
/// </summary>
/// <param name="value">The object to remove from the cache.</param>
/// <returns>A value indicating success or failure of the operation.</returns>
public static bool Remove(T value) {
string key = null;
foreach(KeyValuePair<string, T> item in values){
if(item.Value.Equals(value)) {
key = item.Key;
break;
}
}
if(key == null) return false;
return values.Remove(key);
}
/// <summary>
/// Removes any items from the cache where the item meets the condition specified.
/// </summary>
/// <param name="condition">A delegate which processes an item and returns a boolean value
/// indicative of whether or not the value meets a condition.</param>
public static void Remove(Predicate<T> condition) {
string[] keys = new string[values.Count];
values.Keys.CopyTo(keys, 0);
foreach(string key in keys) {
if(condition(values[key])) values.Remove(key);
}
}
/// <summary>
/// Removes any items from the cache where the key meets the condition specified.
/// </summary>
/// <param name="condition">A delegate which processes a key and returns a boolean value
/// indicative of whether or not the value meets a condition.</param>
public static void Remove(Predicate<string> condition) {
string[] keys = new string[values.Count];
values.Keys.CopyTo(keys, 0);
foreach(string key in keys) {
if(condition(key)) values.Remove(key);
}
}
/// <summary>
/// Removes all items from the cache.
/// </summary>
public static void Clear() {
values.Clear();
}
#endregion
#region Enumerators
/// <summary>
/// Gets an enumerable collection of all the objects stored in the cache.
/// </summary>
public static IEnumerable<T> Values {
get {
return values.Values;
}
}
/// <summary>
/// Gets an enumerable collection of all the keys that identify objects in the cache.
/// </summary>
public static IEnumerable<string> Keys {
get {
return values.Keys;
}
}
#endregion
}
The Cache<T> class generally performs the same function that a statically declared Dictionary<TKey, TValue> object would, but it can be more convinient to write code with, and, again, the use of keys is optional.
Unfortunately, because of a technical issue (overloading), Cache<string> will be difficult if not impossible to use.
Here is an example of using the Cache<T> class.
C#:
public void Example(){
// It could be handy to cache bitmaps that will be used application-wide.
Cache<Image>.Add("OpenIcon", Image.FromFile(IconPath.OpenIcon));
Cache<Image>.Add("CloseIcon", Image.FromFile(IconPath.CloseIcon));
// Be careful--generics do not respect inheritance.
// (They can't due to the way that .Net handles static members of generic classes.)
// Throws exception because object is not cached in Cache<Bitmap>.
Image OpenImage = Cache<Bitmap>["OpenIcon"];
// Works
OpenImage = Cache<Image>["OpenIcon"];
// Cache is enumerable.
// Let's display the contents of Cache<Image> using an image displaying form.
foreach(string key in Cache<Image>.Keys) {
// Create the form with the key for the caption and the associated image within the form.
frmImageDisplay = new ImageDisplayForm(key, Cache<Image>[key]);
// And show.
frmImageDisplay.ShowDialog();
}
}