Click here to Skip to main content
15,867,935 members
Articles / Containers / Virtual Machine
Article

Observable property pattern, memory leaks, and weak delegates for .NET

Rate me:
Please Sign up or sign in to vote.
4.96/5 (42 votes)
4 Dec 200624 min read 215.3K   359   174   46
This article is dedicated to the observable property design pattern, a very nice pattern used in the Microsoft .NET Framework, a possible memory leak problem with it, and gives a couple of ways to solve it.
  1. Warning.
  2. Introduction.
  3. Observable property design pattern in .Net.
  4. Memory leaks.
  5. Partial solution number 1.
  6. Partial solution number 2.
  7. Weak delegates.
  8. Weak delegate decorators factory.
  9. Further improvements.
  10. Sample projects.
    1. UnsubscribeTest sample project.
    2. WinFormsIdleTest sample project.
    3. ConsoleTest sample project.
  11. Lessons learnt.
  12. Conclusion.
  13. License.
  14. Links.
  15. History.

Warning.

While reading this article you should keep in mind that I rather freely operate some terms and use:

  • event source;
  • observable;
  • model

as synonyms and:

  • event sink;
  • event listener;
  • observer

also as synonyms. Although in general it's not true, in the context of the article I assume it is.

Introduction.

One of the things that still excites me most in Microsoft's .Net Framework is the delegates. They make a programmers life a lot easier when it comes to implementing various callbacks and notifications.

I have some experience in Java (though a bit outdated) and I remember my frustration over the Java Beans event model. To make an object notify listeners about the object's state changes you have to declare an event callback interface, implement it in the listeners and keep track of them somehow. While designing of the interface you have to decide how many callback methods should the interface declare because if later on your decide to add a couple more notifications you'll have to create another callback interface and, possibly, rewrite all your listeners. At times like that I had been recalling good old C function pointers. And then Microsoft introduced the delegates.

A delegate is essentially a type-safe object-oriented method pointer. A delegate can be singlecast, thus it points at a single method of a single object (very good for callbacks), or multicast thus pointing at many methods of various objects or even at many methods of a single object (very good for event notifications).

Although delegates are classes, you can do a little without help of the compiler. You can declare new delegate types with special syntax, create delegate instances, assign, add and subtract them and you can invoke them in turn invoking their target methods. You cannot subclass delegates (they all are sealed). But to tell the truth - do you really need it?

Observable property design pattern in .Net.

The delegates take crucial part in notification scenarios. For instance, you can notify some object that a value of a property has been changed. Microsoft in the documentation on Windows Forms programming suggests following pattern for controls and components:

  1. Declare a property with getter and setter; for instance, Value property:
    C#
    object _value;
    
    public object Value
    {
        get
        {
            return _value;
        }
        // Setter goes below
    }
  2. Declare an event with type EventHandler and name
    ValueChanged
    
    that gets raised when the value of the property changes:
    C#
    public event EventHandler ValueChanged;
  3. Write a protected method OnValueChanged that raises the event:
    C#
    protected virtual void OnValueChanged(EventArgs e)
    {
        EventHandler handler = ValueChanged;
        if(null != handler)
            handler(this, e);
    }
  4. Write a proper setter code:
    C#
    set
    {
        if(_value != value)
        {
            _value = value;
            OnValueChanged(EventArg.Empty);
        }
    }

Although this code seems to be verbose, in more complex scenarios this verbosity pays off, because the pattern is very flexible. Windows Forms library extensively uses it to notify the forms about their child controls state changes. For instance, the Control class has a property Font and a respective event FontChanged. When the font changes, the form and other listeners subscribed for the event become aware of the change.

You can view a property and it's change event as a single entity very similar to the Smalltalk's ValueModel class but a bit more effective because a class may have many independent observable properties. If you utilize the pattern in your own code, it would help you to separate the data and it's presentation. If your data object has a public property Salary of type decimal and an event SalaryChanged of type

EventHandler
, you can manually "bind" the property to a text box on the form: the form itself subscribes for the SalaryChanged event of the data object and for the TextChanged event of the text box and passes/converts the values from the UI to the data object and vice versa. So if the data object changes the value of the Salary property, the value in the text box gets changed accordingly, and if the user enters a new salary, the value of the Salary property also changes. I'm talking about rather old but very powerful and still usable pattern named Model-View-Controller or MVC for short. The model here is our property with the event, the view is the text box and the controller is the form, or it's two event handlers, to be precise.

The good thing is that you can bind the the property/event pairs and UI elements with the standard data binding (NB: it is more oriented on IList and DataSet-based data objects) or with Marc Clifton's "simplified data binding" (see http://www.codeproject.com/csharp/simpledatabinding.asp [^]). I've been using a set of classes similar to Marc's BindHelper but a bit simpler and with optional designer support. Also I usually declare for my Windows Forms programs a global singleton object Options that keeps all the program options (who could've imagine). All or most properties of the Options object implement the pattern. It gives me ability to open up an options form that "binds" itself to the properties and lets the user to edit them on the fly. Moreover, because other forms of the program are also bound to the Options object, many things in the interface change immediately, so the user can "play" with the applications settings and see the changes right away. Such options form do not require OK, Cancel or Apply buttons, only a Revert button that discards all the changes and return everything to the previous state (this implemented with use of a GoF [^] design pattern, Memento [^]). Applications that utilize this approach don't feel like Windows applications, but they are definitely convenient.

Also note that in the System.ComponentModel namespace you find a very useful delegate type CancelEventHandler with accompanying CancelEventArgs argument class. With it you can create constrained properties, the properties with values that cannot be changed at certain circumstances. To make the Value property constrained, you need to declare another event, ValueChanging of type

CancelEventHandler
and fire it before actual value assignment. If any of the event listeners changes the value of the Cancel property of the argument object, the setter should leave the value and return.

Memory leaks.

But you have to pay for everything, especially for comfort. While this "live update" scenario is very nice and convenient, there is one annoying thing - you have to track all your event subscriptions. If your form registers a handler for ValueChanged event, you have to unregister it at some point, because delegates are strong references to the event sinks and if the event source outlives the event sink, the latter stays in memory. Even in a middle size application the subscriptions can be hard to trace and you might just forget to unsubscribe from an event (it is so-called "split cleaner" error pattern).

The sad thing is that you may really get used to the fact that CLR manages memory. The code generated by UI designers never unregisters event handlers. All this might make you think that the delegates work in "fire and forget" fashion.

Partial solution number 1.

Suppose you have an event source object that exposes a lot of events and many event sink objects that subscribes for many of them. When the event source goes out of scope, it is a good idea to unsubscribe all event sinks at once. It can easily be done. If you event is declared like:

C#
public event EventHandler PropertyChanged;

you should change this declaration to:

C#
EventHandler propertyChanged;

public event EventHandler PropertyChanged
{
    add
    {
        propertyChanged += value;
    }

    remove
    {
        propertyChanged -= value;
    }
}

Why would you do that? Because if some objects have subscribed for the

PropertyChanged
event you can unsubscribe them at once by just assigning null to the delegate storage field propertyChanged:

C#
public void Unsubscribe()
{
    propertyChanged = null;
}

Simple, isn't it?

In case you use co-called optimized event implementation with the

EventHandlerList
class in the Unsubscribe() method you may just recreate the event handler list, unsubscribing from all the events at once. Event simpler.

Partial solution number 2.

Suppose the scenario above doesn't suite you needs and you have to unsubscribe only one observer from all the events exposed by the observable. Let's the event source manage the removal.

First, we need a simple utility class:

C#
public sealed class DelegateUtil
{
    . . . . .

    public static Delegate Unsubscribe(Delegate del, object target)
    {
        if(null == del)
            return null;
        if(null == target)
            return del;
        Delegate[] list = del.GetInvocationList();
        for(int i = 0; i < list.Length; i++)
        {
            if(target == list[i].Target)
                list[i] = null;
        }
        return Delegate.Combine(list);
    }
    . . . . .
}

The Unsubscribe() method removes all delegates that point at any method of the target object from the multicast delegate del. I.e. when a particular event sink target goes out of scope the event source removes all references to it from the event delegate. Let me show how to use this snippet using a class that declares our Value property:

C#
public void Unsubscribe(object target)
{
    Value = (EventHandler)DelegateUtil.Unsubscribe(Value, target);
}

If you class exposes other events, repeat DelegateUtil.Unsubscribe for every event. Keep in mind that the actual code depends on the event implementation (see EventHandlerList class description in .Net Framework SDK documentation for details), but it works. We have replaced a bunch of -= operators with a single call.

Weak delegates.

If the event sink object does not know exactly when it goes out of scope, i.e. it is neither a control, nor a component, nor it implements the

IDisposable
interface, the tricks above won't work and the sink object will stay in memory. This wouldn't be the case if the delegates were actually weak references. You wouldn't need to unsubscribe from the events at all. But had Microsoft really made delegates weak, we would have a lot of horrible time debugging managed callbacks for various unmanaged APIs. It would be nice if some day Microsoft adds weak delegates support to .Net but only as additional feature.

But is it possible to somehow emulate weak delegates at all? Of course!

Greg Schechter in his blog presents an implementation of classes very close to weak delegates: http://blogs.msdn.com/greg_schechter/archive/2004/05/27/143605.aspx [^]. Actually I highly recommend to read his post, he describes the problem with event delegates very thoroughly and with great diagrams that make the picture much clearer.

He introduces an object that decorates a delegate making it behave as if it was a weak one (Greg calls it the WeakContainer). The decorator receives the notifications from the observable on behalf of the observer and keeps a weak reference to the observer. When the observer goes out of scope and gets garbage collected, the decorator unsubscribes itself from the notifications and becomes eligible for the garbage collection itself. The observable knows nothing about it or the fact that it sends the notifications to an intermediate object instead of the observer.

Ian Griffit in his blog answers to Greg's call and tries to implements a generic weak delegate: http://www.interact-sw.co.uk/iangblog/2004/06/06/weakeventhandler [^]. The problem with his code is that he keeps a weak reference to a usual delegate, so the delegate and the observer object get garbage collected too soon.

Xavier Musy offers a working solution: http://www.seedindustries.com/blog/x/2004_06_01_archive.html [^]. He essentially reimplements the MULticastDelegate class using a weak reference instead of usual reference for the Target property. The only bad thing is that he uses the MethodInfo.Invoke method which is painfULly slow. While it might be of little concern for an average Windows Forms application, in some cases like mULtiple views receiving notifications from the same model it might be inappropriate.

Weak delegate decorators factory.

In my opinion, Greg Schechter's solution is almost perfect. The only problem with it is that the decorator must know too much about both the observable and the observer. It has to know at least their types, the event and the event handler. So you cannot make it generic, even in .Net 2.0, and have to reimplement it for each event of each event source class. But if you take a close look at the Greg's code you'll notice that the implementation of the decorator is simple, if not trivial. The finalizer there is just for sample, so you need a constructor and the method with signature identical to the target method. If it is that simple, it would be easy enough to create such objects on the fly. Do you remember the word "thunk"?

Enter System.Reflection.Emit and WeakDelegateDecorator. The methods of the latter class perform the actual code generation using the former namespace. But before we start actually code the IL emitting, let's consider possible event wiring scenarios:

  1. Instance event is wired to an instance event handler;
  2. Instance event is wired to a static event handler;
  3. Static event is wired to a instance event handler and
  4. Static event is wired to a static event handler.

In the scenarios 2 and 4 it doesn't matter what kind of delegate we are using, the delegate target lives as long as the application domain lives. So we basically need to consider scenarios 1 and 3. The scenario no. 1 is related to the MVC pattern and data binding, the scenario no. 3 is very well known to anyone who ever (mis)used the Application.Idle event.

Let's imagine that we have an event source object with property Name and event NameChanged, and an event sink object with the method OnNameChanged with proper signature, of course, that gets called when the NameChanged event is raised. Let's write a weak event decorator class for such scenario:

C#
public class WeakInstanceToInstance: WeakReference
{
    public WeakInstanceToInstance(EventSink observer):
        base(observer)
    {}

    public void Handler(object sender, EventArgs e)
    {
        EventSink observer = (EventSink)Target;
        if(null != observer)
            observer.OnEvent(sender, e);
        else
        {
            EventSource observable = sender as EventSource;
            if(null != observable)
                observable.Event -= new EventHandler(Handler);
        }
    }
}

This class or more specific, it's translation to IL instructions, is going to be our template for scenario 1.

Let's imagine how an object, probably a form, gets wired to

Application.Idle
event. The object would have a method like OnIdle and the weak decorator would look like:

C#
public class WeakStaticToInstance: WeakReference
{
    public WeakStaticToInstance(EventSink observer):
        base(observer)
    {}

    public void Handler(object sender, EventArgs e)
    {
        EventSink observer = (EventSink)Target;
        if(null != observer)
            observer.OnIdle(sender, e);
        else
            EventSource.StaticEvent -= new EventHandler(Handler);
    }
}

The code for scenario 3 is a bit simpler but they share a lot.

While Microsoft uses and recommends to use for events delegates signatures two parameters, the first of type object and the second derived from EventArgs class, there is no restriction on number of parameters for an event delegate and there are exceptions. Take a look at AbstractMargin.cs file from SharpDevelop IDE source code (src\Libraries\ICSharpCode.TextEditor\src\Gui\AbstractMargin.cs). I have to take this into account. I also should remember that event delegates might return results. If these results are reference types, everything is easy, we should return null, for some value types built-in to the MSIL I may use built-in instructions, and for the value types in general I should use the default constructors that create uninitialized structures.

Given proper info, the overloaded method Decorate generates the proper weak decorators for specified events and returns a delegate that should be wired to the source event:

C#
public static Delegate Decorate(Type eventSourceType, string eventName, 
           Delegate del)
public static Delegate Decorate(object eventSource, string eventName, 
           Delegate del)
public static Delegate Decorate(object eventSource, string eventName, 
           object eventSink, string eventHandlerName)
public static Delegate Decorate(Type eventSourceType, string eventName, 
           object eventSink, string eventHandlerName)
public static Delegate Decorate(EventInfo eventInfo, Delegate del)
public static Delegate Decorate(EventInfo eventInfo, object eventSink, 
           string eventHandlerName)

You usually decorate event delegates by replacing code like:

C#
eventSourceObject.Event += 
               new SomeEventHandler(eventSinkObject.EventHandlerMethod);

with:

C#
eventSourceObject.Event += 
       (SomeEventHandler)WeakDelegateDecorator.Decorate(eventSourceObject, 
                           "Event", eventSinkObject, "EventHandlerMethod");

or with more type safe (and memory consuming) version:

C#
eventSourceObject.Event += 
       (SomeEventHandler)WeakDelegateDecorator.Decorate(eventSourceObject, 
         "Event", new SomeEventHandler(eventSinkObject.EventHandlerMethod));

I wanted to make the WeakDelegateDecorator class generic for .Net 2.0 so some Decorate overloads would return typed delegates, but unfortunately C# 2.0 does not allow to specify the Delegate as the base class for generic constraints. So we have to live with these type casts.

These Decorate methods check parameters and call the private method

InternalDecorate
. The method first tries to find already registered weak decorator type in it's internal cache and only if the combination of it's parameters is a new, it creates a new weak decorator class and keeps it's type for later use.

Keep in mind that the event handler methods must be public. This is because in .Net a class that resides in another assembly cannot access non-public memebers of your class. It is a limitation of the weak delegates and I'm not aware of any workaround.

Each decorator class has two methods - a constructor and an event handler.

The constructor method is simple, it just passes the reference the the event sink object to the base class (the WeakReference) constructor. But for the handler method I use various optimization techniques for non-trivial delegates. For instance, the MSIL has special instruction that reference the first four arguments of the method. Because our handler is the instance method, the very first parameter with index 0 is the this pointer and I use ldarg 0 instruction to put it to the stack. For the most common case the sender and the event arguments object have 1 and 2 indices. If the handler has more than 3 arguments, I use ldarg.s {index} instructions. There is also ldarg {index} instruction, but it is for the methods with more that 256 arguments. I believe that a person who tries to write methods with this many arguments should not be allowed to use a computer.

I add the tailcall prefix to some call/callvirt instructions: to the call to the event target method and to the

remove_{Event}()
call if the method does not return value. In both cases the original code returns immediately; the tail call optimization effectively "reuses the stack" of our handler method. For x86 processors the JIT should replace call/leave instruction pair with simple jmp. It definitely makes the decorator faster in most common cases. On one of my test computer (with Intel CPU and Windows 2000) it gives the code good performance boost, on another (AMD 64 and Windows XP) doesn't change the picture. However, according to this blog post: http://blogs.msdn.com/shrib/archive/2005/01/25/360370.aspx [^] by Shri Borde, tail calls in .Net may cause problems so may I'll have to remove this optimization in the long run.

Yet another optimization is use of predefined MSIL instructions for basic value types. For a generic value types, even for low-level IntPtr and UIntPtr types (they mapped to MSIL as native int and native uint repectively) I use the default constructors.

I have changed the Builder class to loosen security restrictions for the decorators - essentially I've made the handlers public. Now you can use the Pvax.WeakDelegates.dll assembly in applications that run in the LocalIntranet security zone (i.e. run from a UNC share), not only in FullTrust zone.

My implementation of weak decorators differs from Greg's. Greg's containers/observers keep references to "weak containers" and attach events of many observables to a single mediator that relays the events to the observer (I've redrawn Greg's diagram):

Sample image

In my implementation the observes and the observables do not know about mediators at all so I have to create a new decorator class for each new event/handler combination:

Sample image

Greg's approach is better in terms of memory consumption.

I considered to use .Net 2.0 dynamic methods as a lightweight replacement for the decorators, but it seems to me that they don't fit in the picture. Please, prove me wrong, it'd be nice to get rid of this clunky in-memory type cache. If you ask me why I don't use generic hash tables, I have two answers. First, the code is written for .Net 1.1. Second, just imagine yourself the declaration of the cache with generics.

I've introduced a set of new tests that prove the weak delegate decorators work for .Net 2.0 generic delegatess. I had been worrying a bit that I'd have to change or tweak the IL code generation for generics somehow. To my surprise the code written for .Net 1.1 worked with generics without any change. It means that Microsoft's developers had done a amaising piece of job seamlessly integrating generics into CTS and CLR. Excellent!

By the way, after writing tests for generic delegates I don't consider declarations of reflection-based factory methods ugly: declarations and casts for more or less complex generic delegates are uglier.

Further improvements.

My code generates a lot of types, it would be a good idea to generate as many event handlers per decorator as possible to reduce the number of types and the total number of decorators.

My code is inherently not thread safe; it would be nice to make it so.

If the IL code generator throws an InvalidProgramException, it means that I screwed up something in the IL code (not that I think I did but it might happen). This is unrecoverable exception because the in-memory assembly that gathers all the decorator types becomes corrupt. I do not catch this exception and let it propagate up to the global exceptions handler. If this happens, the most reasonable way is to let the application terminate and notify me. If you have access to the application's source code, please end me at least the declaration of the delegate which invocation causes the error.

Sample projects.

As usual, my sample project is created in SharpDevelop IDE. The project contains five subprojects: Pvax.WeakDelegates, Pvax.WeakDelegates.Tests, WinFormsIdleTest, ConsoleTest and UnsubscribeTest. I've also converted them to VS-compatible projects with #D 2.0.

The first two are the weak decorators library itself and the tests assembly for the library. The rest are described below.

The sample project folder also contains FxCop and NUnit project files. FxCop fairly says that the Pvax.WeakDelegates namespace contains too little classes, but keep in mind that all decorators are emitted in this namespace also. It also is not happy about static constructors and ToString() calls without specifying the culture info, but all these are "implementation details", so just ignore them. I created a separate NUnit project because I somehow screwed up my #D installation and the unit testing add-in doesn't work anymore. If the compiler complains about missing reference to the NUnit.Framework assembly, remove the reference, add it again and recompile the test project.

UnsubscribeTest sample project.

This sample consOLe application illustrates the DelegateUtil class usage. It creates an observable instance and some observers, changes a property of the observable, unsubscribes one observer unconditionally with the DelegateUtil and changes the property one more time. All notifications are logged to the consOLe to make sure that the observer has really been unsubscribed.

WinFormsIdleTest sample project.

The WinFormsIdleTest is a sample of the weak delegates usage in a Windows Forms application. I hook child forms to the Application.Idle event. Although the forms get disposed of at the WM_CLOSE message handlers, the memory occupied by them stays reachable (i.e. not eligible for garbage collection) because of unsubscribed events. If you decorate the event delegates with the weak decorators, the memory gets reclaimed.

The sample application consists of two forms. The main form:

Image 3

has three buttons. By clicking the New sticky form... button you create a small form:

Image 4

It performs a simple animation using Application.OnIdle event (NB: never use this event for that purpose in real applications, it is highly ineffective). The Click event handler for this button uses usual += operator to subscribe the child from for the idle event. You can close the child form with the standard Close button (the small button with diagonal cross in the right side of the window's caption).

If you look at the code, you'll see that the child form constructor allocates an array of bytes to Simulate the real application's data. I allocate a 100 Kbytes from the large heap, because the memory manager considers objects that big "large". It is very convenient to watch these allocations using the Performance Monitor application:

Sample image

Add, for instance, following counters:

  • # Bytes in all Heaps, scale 0.00001:
    Image 6
  • Large Object Heap Size, scale 0.00001:
    Image 7

If while running the program, you should create a couple dozens of child forms with the New sticky form... button, you should see a picture similar to:

Sample image

Now close all the child forms. Their respective Dispose() methods will release window handles associated with the forms, but because all these forms have strong references to them from the static event, they stay in memory. And, of course, the byte blocks they own also stay in memory. Click Force GC! button to make the GC to reclaim all unused memory (NB: never do anything like that in a real program). You'll see a picture in the Performance Monitor similar to:

Sample image

I've marked with light green line the moment I clicked the button. As you see, the size of the large heap doesn't change and we obviously have a memory leak here.

Restart the sample application and repeat all the steps except this time click the New weal sticky form... button. The event handler for this button is almost the same, but it uses my WeakDelegateDecorator class. The Performance Monitor graph after allocating a fair number of the child forms should look like:

Sample image

Now close all the child forms and click Force GC! button. After that the graph should look like:

Sample image

Again, I've marked with light green line the moment I clicked the button. As you can see, with weak event decorators the memory gets reclaimed as it should be.

ConsoleTest project.

This sample project illustrates the property observer and constrained property patterns. It tests a way to unsubscribe all the observers from the events at once. It works because the Observable class instance outlives the instances of the Observer class.

It also tests the weak delegates decorators. An interesting detail: at weak decorators tests you are going to see that while the event sink objects get garbage collected, the decorators themselves stay in memory up until the moment when the code raises the events again. Only at that moment the decorators become aware that their targets are not reachable anymore and unsubscribe themselves from the source events. This tests show how much slower the decorated delegates are in comparison with undecorated.

You can play with various constants like HogSize,

MemoryNoiseObjectCount
, ObserversCount and
PropertyChangeCount
. For instance, the MemoryNoiseObjectCount constant defines how many "memory noise" objects should be allocated by the GenerateMemoryNoise() method. This method Simulates a real-world memory manager load. By changing the constants you will get different results, there's one thing that doesn't change - the weak decorators eat additional memory and make the delegate calls slower, so use them wisely.

It is interesting to run the ConsoleTest under CLR Profiler [^]. To minimize the memory stress, set the MemoryNoiseObjectCount to 0. If you do so, you'll see an enormous number of delegates generated by the application. This is because += and -= operators are rather ineffective in mass event subscription scenarios, so if you are going to subscribe a lot of object for an event at once, use the overload of the

Delegate.Combine()
method that takes an array of delegates as it's parameter. On the other hand, it shows effectiveness of the .Net garbage cOLlector because despite the fact that subscription generates a lot of small objects, the time that the subscription takes depends almost linearly on the number of the subscribers.

Lessons learnt.

Because the delegates are immutable, using += and -= operations on them repeatedly generate a vast amount of small objects (singlecast delegates) that have big chances to be promoted to heap generation 1 and even generation 2. In other hand, null is a valid delegate object. That's why my DelegateUtil.Unsubscribe() method just nullifies the slots in the original delegate's invocation list and uses the Delegate.Combine() method: this trick minimizes the number of intermediate objects during the process of the new delegate creation.

MSIL and System.Reflection.Emit at first glance look scary but in practice are even simpler than System.CodeDom. The virtual machine that "executes" the IL code is a simple stack machine, and the intermediate language itself reminds me of Forth so I feel at home here. I'm not quite sure about really big projects but in this particular one it took me only two days to write the IL emitting code that worked. Anyway, thanks to Microsoft that made this great feature available for an average programmer.

You know it, but I repeat - unit tests are useful. They helped me to find and squash two nasty bugs in the IL code generator. Both bugs were related to value objects that the decorators' event handlers had to return.

Conclusion.

Delegates are great, no doubt. Their use makes the source code clearer and object models of our applications more flexible. There is, however, a flip side of this coin. We cannot get rid of it, but we can simplify our tasks with

DelegateUtil
class and weak delegate decorators.

License.

The DelegateUtils class is covered by BSD license (see the source code). Because the weak delegates decorator factory code is based on Greg Shechter's sources and ideas and because I borrowed some from MSDN, I put the Pvax.WeakDelegates assembly and it's source under MIT license. Use it, however, on your own risk, I haven't tested it in all possible scenarios.

Links.

History.

  • 11/01/2006 - initial version;
  • 11/13/2006 - tail call optimization added; the Builder class code changed to loosen permission restrictions - now the decorators' factory works in the LocalIntranet security zone.
  • 4/12/2006 - .Net 2.0 project options fixed; differences in the resource handling between #D versions eliminated; INotifyPropertyChanges and EventHandler<T> compatibility ensured for WeakDelegateDecorator; internal methods and objects refactored a bit; added two new overloads for the Decorate method.
  • 14/01/2007 - generic delegates compatibility ensured; project layouts are changed slightly; a new subprojects has been added to test bxb error report.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Russian Federation Russian Federation
I'm a system administrator from Moscow, Russia. Programming is one of my hobbies. I presume I'm one of the first Russians who created a Web site dedicated to .Net known that time as NGWS. However, the Web page has been abandoned a long ago.

Comments and Discussions

 
GeneralThread safety Pin
Thomas Hamilton24-Oct-08 8:30
Thomas Hamilton24-Oct-08 8:30 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.