We all know that there are no extension properties. Extension methods, yes - but no extension properties. If this has already been a problem to you, this article might be a solution.

Of course, you should prefer the "clean" way and extend your types if you need new properties. But that is not always possible - there are sealed classes within the .net framework or within third party assemblies. Or it just seems to be an overhead to extend a type for using that property in only one case. To make it short, I will not discuss the pros and cons about extension properties - you can use them just as you like.

But I will give you an example:
I had to implement a module where all kinds of types came in - maybe once, maybe twice, do not know how often. But I had to recognize an instance the second time it came in. So I wanted to add a "ticket" to any instance. Something as followed would be nice:

Of course, without theIncomingReference having implemented "TicketID" or "TicketTime" as a property!

Just in case I could benefit from others work, I searched the internet for extension properties. No direct support was found. I came across Mixin. But that was not what I was looking for. You will have to use interfaces and factory methods - not as generic as I wanted it to be. There was really no solution for me. So I did it my way (good old Franky) and came up with the UniversalTypeExtender.

Again, there is no support for extension properties out of the box. So we will have to emulate this. This is done by "binding" a reference of a type (e.g. Ticket) to the extended object (e.g. theIncomingReference). This "binding" is stored and it is used again on every request on the extended object. So, actually you work with properties of the "binding" object instead with properties of the extended object. The trick is that you always get the same "binding" object instance for the same extended object. Sounds easy? Yes, but of course there are a few things to take care of - like garbage collection. We will have a look at this, soon. But first, a class diagram showing the components of the UniversalTypeExtender:

You can see the "binding" object in the class diagram. It is called RepositoryItem and comes as a nested class within its related ExtensionRepository. A RepositoryItem holds a reference to the extended object and the extensions of this object. The ExtensionRepository keeps track of these RepositoryItems. The UniversalTypeExtender itself provides only one extension method - Extended<T>(). This method returns an Extender for the object to extend. The Extender in turn manages the different ways of extending an object - for now, Dynamically() and With<TE>(). Dynamically() returns a real dynamic object (DynamicPropertyExtension) - that is why you can call any property without setting up anything else. With<TE>() returns an instance of the specified type - that gives you type safe coding.

So, that was a short overview. Let´s have a deeper look at each of these components.

As already mentioned, all you have to do in order to extend an object, is to call the extension method Extended<T>(). That was really obvious because extension methods are the only way to add own functionality to any type without touching its code. By using the generic type T, we can control that extensions only work on reference types - that means classes. It would be problematical on value types because they are mostly given by value. But the concept behind the extender needs references as you can see later on. Extended<T>() returns an Extender which gets a reference to the extended object. So the code looks really simple:

As you can see, the real work is delegated to the repository. For that, the With<TE> forces TE to provide a parameterless constructor because the repository has to create a new instance of TE on its first request. Also, you can see that Dynamically() just calls With<TE> with a predefined type - DynamicPropertyExtension, at which we will come back later on.

You might wonder why I introduced the Extender instead of just implementing proper extension methods on the UniversalTypeExtender. I wanted the extension method Extended() to be limited to reference types. So I had to define Extended<T>() with T being limited to classes. You do not have to think about T - just type Extended(). But if I had to define TE (from With<TE>()), too - like Extended<T, TE>() - you would have to specify T on any call. I did not like that, that's all Consider the Extender to be part of a tiny fluent interface.

Locking is used because the repository has to make sure that a call gets a "safe" view at the item list. Imagine, a call would create a new item because the requested item is not there, yet. And at the same time - before the new item is added to the item list - another call would do the same. That would end up in two extension items for the same object! But that would bypass our concept - so we lock.

GetOrNew iterates the inner list, looking for an item which belongs to the requested instance. If no item was found, it is created. If an item was found, it is moved to the beginning of the list. That is because it is supposed that an requested item is used again, shortly. That might speed up things within a huge list.

Before we will inspect the RepositoryItem, we will have a look at garbage collection. This is the .net way of freeing the memory of unused objects. If you have not heard about that before, you can get more information here. Important to know is that it removes "unused" objects. That means objects which are not referred any more. Now, have a look at our repository again: all created items are stored in the inner item list. That means, this list is getting bigger and bigger. Because all these items are referred in one way - at least from the list itself - there is no automatic garbage collection from the framework. So we will have to care about this on our own. And of course, we do!

If you dig into the ExtensionRepository's code you will notice that there is a timer which looks after garbage from time to time:

This method asks every item if it could be collected (how the item itself knows about this is described soon) and removes it, if so. Again, watch out for locking! You can figure out when the timer starts and stops on your own. Garbage collection seems to be just a tiny part of this article but it really is an important part of the UniversalTypeExtender.

Now let's inspect the RepositoryItem. It holds a reference to an extended object and references to all extensions requested for this object. As you can see, the reference to the extended object is stored as a WeakReference:

If it would be stored as a "normal" field - that means as a strong reference - it would never be collect by the garbage collection, as mentioned above. But WeakReferences give you the ability to hold a reference by allowing it to be collected if there is no other strong reference to it anymore. So, you can check if a reference is still alive:

publicbool CouldBeCollectedByGC {
get { return !mTarget.IsAlive; }
}

Fine!

If an extension is requested, there are nearly the same things to do like described for the repository: locking, searching within the list, creating an instance, and so on:

As shown at the beginning, you can extend an object by calling theIncomingReference.Extended().Dynamically(). Then, you can type any property name as you want and set it to any value you like. Is it a miracle (good old Freddy)? If you know the DynamicObject from .net 4, you already know the answer, which - of course - is: no! The DynamicObject let you implement dynamic property access. There are special methods you can override, building the getter and setter of your properties. In this case, the values are stored within a private list - of course with their property names:

The code makes use of Code Contracts and FluentAssertions for testing. So you will have to install them - both for free - in order to compile and test the source code. But the final DLL can be found in the bin-folder - ready to use. Just reference it and distribute it with your final binaries. The UniversalTypeExtender comes as an extension method. You will have to reference to the TB.ComponentModel namespace in order to use it.

Extensions you want to use by the With<TE>() method will have to implement a parameterless default constructor.

As you have seen, the objects are not touched in any way. The extensions are just stored within a static list. That means, that e.g. serialization will not work. So, putting an extended object into the ViewState of an aspx page - in hope of getting the extensions back on a postback - will not work, of course. Whereas storing an object in a Session should do fine.

Just for interest, I did a little setup for testing the performance. This test was done on a Core Duo 2.67 GHz with 3 GB RAM. During the test 10.000 objects were created and each of them was extended. Then these 10.000 objects were looped again and the extension was read for each. The garbage collection of the UniversalTypeConverter was called during the test. The average duration of the test was about 8.5 seconds. For 20.000 calls this means about 2.353 calls per second.

While using WeakReferences I had to handle them in my unit tests. That means, I had to control that they were collect by garbage collection, so that I could verify some actions within my code. Normally, you could not - and you should not! - control the time of collecting by yourself. You can trust the runtime - it knows best, when to do this. But for testing, you will have to control it. Therefor, you can call GC.Collect() as you can see it in some of my tests.

I have seen lots of conversations about the normal way to add extension properties (just over the last couple of weeks actually, I am lucky enough to see some of these internal Microsoft mail), and from those talks/emails the common method appears to be by using ConditionalWeakTable.

I have knocked up a small demo for you, took like 5 mins, so not that elegent, but you could build on this, and it already deals with direct lookup, weak references, etc etc

I'm really happy, that YOU took the time to have a look at it! Thank you very much for your snippet.I'll have to admit that the ConditionalWeakTable seems to be something I should have come over during my research. But I did not. However, that's what I like on codeproject - there is always someone with a great tip. At this time, I'm not sure if I'll change my implementation - but I like getting new input for future projects - so your comments are always more than welcome!

"Still great job for getting there by your self, well done"Nice, that you end up with an ego-boost, after all

Gave your article a vote of 4 - nice implementation on a great idea, nice fluent interface. Only reason for the 4 is the poor performance, which can be MUCH improved with a dictionary based implementation, I'm guessing at least 1000x speed improvement on average lookup time on a 20,000 item collection, where the key is the extended object.

You won't want a strong reference on the extended object, but you can wrap it in a KeyWrapper class that holds a weak reference to it and forwards GetHashCode and Equals calls to the extended object so the dictionary still works properly.

Hello Mike,at first, thank you for voting. A 4 is still good, isn't it? But I'll describe you my thoughts I had about this during my implementation:

As mentioned, I wanted my extender to work just "out of the box". No setup, no special requirements. About GetHashCode I read something within the MSDN which looks - with my knowledge - not very suitable:

from http://msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx[^]:The default implementation of the GetHashCode method does not guarantee unique return values for different objects. Furthermore, the .NET Framework does not guarantee the default implementation of the GetHashCode method, and the value it returns will be the same between different versions of the .NET Framework. Consequently, the default implementation of this method must not be used as a unique object identifier for hashing purposes.

I did not want the user to be aware of such things. I would like to correct my concerns, if I'm wrong. So if you have any information about this, please keep up posting your comments.

Dictionaries are built with all that in mind, the user doesn't have to worry about any of that. As long as Equals and GetHashCode are both forwarded to the object stored by the WeakReference, the dictionary will work as intended. User observed behaviour will match exactly with your current implementation.

GetHashCode doesn't have to be unique - the dictionary stores a list of objects that match each hashcode. The dictionary gets your object by iterating through the list of objects that match the key's hash code and comparing with Equals(). Dictionary works much better with a good hash code implementation that evenly/"randomly" spreads out hash codes in the available space (32 bits), but even if your hash code always returned 1 it would still work, just slow down to the speed of a list.

You can choose to also optimize by making the list of extensions for each object in the RepositoryItem a dictionary where the key is the extension type, although that would only provide a performance increase for objects that have more than 5 or 10 types of extensions, which is probably a pretty rare case.

that will repeatedly call Extended() on the same object, you can store a variable called something like "lastObject" and "lastRepository" so that you can avoid the dictionary lookup entirely if it is the same as the last one accessed.

Either that, or if performance is critical then encourage caching the Extended() lookup, as such:

Performance was not really a problem for my scenario. But I did it like in your 2nd suggestion.

I moved the last object to the begining of the list because I had to do some copy actions from one extension to another. This brought up both involved objects to the top of the list. Only one "lastObject" reference would not have done this - as far as I got at this point. But I think by switiching to dictionary, all mentioned "performance-tricks" will be obsolete

Hm, after a deeper look I'm afraid of not beeing able to predict the result from GetHashCode() as a constant value. The MSDN link, provided in my other comment, describes that a hash maybe build by specific fields or properties of an instance:

Hash functions are usually specific to each Type and, for uniqueness, must use at least one of the instance fields as input.

This means that a hash may differ from time to time. But the documentation for the dictionary says:

You are doing exactly that, using one of the instance fields - the KeyWrapper's target.

The only reason the hashcode on the KeyWrapper would ever "change" is if the referenced object went out of scope and was garbage collected, in which case you wouldn't be able to forward the hashcode request. You can take care of that by caching the hashcode when you construct your KeyWrapper (by calling GetHashCode() on internalObj in my sample code).

A hash code on an object should never change, so that's not an issue the user needs to be aware of. Mutable reference types get their hash code from the default Object.GetHashCode() implementation that is based on an internal object-id that never changes. Immutable objects can override that implementation and get a hash code based on field values, but a GetHashCode method should never return different value over the lifetime of the object.

The KeyWrapper object is immutable - once it is constructed, none of the field values can change. Thus, you can override GetHashCode and return one based on a field, i.e. the extended object being used as the key.

Hey, you are really fast on responding It was just a theoretical concern. But sure, I can nobody prevent from programming against conventions. So, as long as a type follows the conventions, everything will work fine.Again, your comments are very meaningful!

If someone doesn't follow conventions in their type, you'll have problems with any approach The current list approach will fail, for example, if someone incorrectly overrides Equals() on a mutable type.

Equals() and GetHashCode() are very important to override correctly if someone decides to do so, and there is lots of documentation and guidelines from MS on how to do that. It's not really that common to have to override those methods, and if someone does, they better make sure they get it right, as they are base object methods utilized all over the framework in many places to support equality checking and indexing

GetHashCode()'s purpose is precisely to enable efficient hash table indexing, so someone should expect code that uses dictionary lookups to fail if it isn't done properly. Just like if someone overrides Equals improperly, they can expect List lookups to fail. I think it would be pretty rare for someone to override a non-obvious method like GetHashCode() without reading the documentation on it first, although I've seen lots of crazy things (many examples in the Coding Horrors section of CodeProject, haha).

I just changed my implementation and now I'm using a dictionary. So perhaps you want to revote? Seriously, thanks for your input! Look at the new performance, mentioned at the end of the article - it is really great!