Sunday, 15 April 2018

# What's in PeanutButter.Utils, part 2

## Metadata extensions

I just wanted to chip away at my promise to explain more of the bits in PB, so I thought I'd pick a little one (though I've found it to be quite useful): metadata extensions.

At some point, I wanted to be able to attach some arbitrary information to an object which I didn't want to extend or wrap and which some code, far down the line, would want to read. If C# was Javascript, I would have just tacked on a property:
```js
someObject.__whatDidTheCowSay = "moo";
```

But C# is _not_ Javascript. I could have maintained some global `IDictionary` somewhere, but, even though I wanted it to support a feature in [NExpect](https://github.com/fluffynuts/NExpect), where the code wouldn't have a running lifetime of any significance, it still felt like a bad idea to keep hard references to things within NExpect. The code associating the metadata has no idea of when that metadata won't be necessary any more -- and neither does the consumer.

Then I came across [`ConditionalWeakTable`](https://msdn.microsoft.com/en-us/library/dd287757(v=vs.110).aspx) which looked very interesting: it's a way of storing data where the keys are weak references to the original objects, meaning that if the original objects are ready to GC, they can be collected and the weak reference just dies. In other words, I found a way to store arbitrary data referencing some parent object and the arbitrary data would only be held in memory until the end of the lifetime of the original object.

That's exactly what I needed.

So was born the [`MetadataExtensions`](https://github.com/fluffynuts/PeanutButter/blob/master/source/Utils/PeanutButter.Utils/MetadataExtensions.cs) class, which provides the following extension methods on all objects:

- `SetMetadata`<`T`>`(string key, object value)`
- `GetMetadata`<`T`>`(string key)`
- `HasMetadata`<`T`>`(string key)`

which we can use as follows:

```csharp
public void MethodWantingToStoreMetadata(
  ISomeType objectWeWantToStoreStateAgainst)
{
  objectWeWantToStorStateAgainst
    .SetMetadata("__whatDidTheCowSay", "moo");
}

// erstwhile, elsewhere:

public void DoSomethingInterestionIfNecessary(
  ISomeType objectWhichMightHaveMetadata)
{
  if (objectWhichMightHaveSomeMetadata
        .HasMetadata("_whatDidTheCowSay"))
  {
    var theCowSaid = objectWhichMightHaveSomeMetadata
                       .GetMetadata("_whatDidTheCowSay");
    if (theCowSaid == "moo")
    {
      Console.WriteLine("The cow is insightful.");
    } 
    else if (theCowSaid == "woof")
    {
      Console.WriteLine("That ain't no cow, son.");
    }
  }
}
```

And, of course, as soon as the associated object can be collected by the garbage collector (remembering that the reference to this object, maintained within PB, is _weak_), that object is collected and the associated metadata (if not referenced elsewhere, of course) is also freed up. This mechanism has facilitated some interesting behavior in `NExpect`, and I hope that it can be helpful to others too.

No comments:

Post a Comment

PeanutButter.RandomValueGen: the builder pattern & random generation for testing purposes

Retrieving the post... Please hold. If the post doesn't load properly, you can check it out here: https://github.com/fluffynuts/blog/...