开发者

Can I make an objects lifetime depend on another object without making a strong coupling in C#?

I have some factory code along the lines of:

public MyHandlingClass Create()
{ 
  var myHandler = new MyHandlingClass();
  var myNotifier = new MyNotifyingClass();
  myNotifier.Notify += myHandler.HandleNotification;

  return myHandler;
}

The idea was to allow the MyHandlingClass to react to external signals without caring about the type of the sender. In different applications the factory class containing the above method could then replace MyNotifyingClass with something else able to raise a similar type of event.

In the actual code, the MyN开发者_运维技巧otifyingClass handles events from an unmanaged DLL:

public class MyNotifyingClass
{
    private EventHandler notify;
    private UnmanagedEventHandler unmanagedNotify;

    public event EventHandler Notify
    {
        add
        {
            this.notify += value;

            // Hold on to a strong reference to the delegate passed into the
            // unmanaged DLL, to avoid garbage collection of the delegate:
            this.unmanagedNotify = HandleUnmanagedNotify;
            NativeMethods.SetNotifyCallback(this.unmanagedNotify);
        }
        remove
        {
            this.notify -= value;
        }
    }

    private void HandleUnmanagedNotify(IntPtr sender, IntPtr eventArgs)
    {
        this.notify(this, eventArgs.Empty);
    }
}

But when I return from the factory method, there are no longer any strong references to the myNotifier instance, and it will eventually be garbage collected, resulting in access violations when my unmanaged DLL tries to invoke the callback.

I would like to somehow enforce that the myNotifier instance has the same lifetime as the myHandler instance. But I don't particularly like the idea of letting the MyNotifierClass holding on to a strong reference to the handler object. After all, it has no further use for the actual object once the wiring is in place...

Can I somehow create a strong relationship between the two classes and still have them not know about each others existence?

(EDIT: To cut a long story short, this code snippet seems to reproduce my problem:)

[TestClass]
public class MyTests
{
  public class MyHandler
  {
    public void Handle(object sender, EventArgs e)
    { }
  }

  public class MyNotifier
  {
    public event EventHandler Notify;
  }

  [TestMethod]
  public void TestsSomeCondition()
  {
    var myHandler = new MyHandler();
    var myNotifier = new MyNotifier();

    myNotifier.Notify += myHandler.Handle;

    var weakNotifierRef = new WeakReference(myNotifier);
    myNotifier = null;

    GC.Collect();

    Assert.IsTrue(weakNotifierRef.IsAlive);
  }
}


When you attach to an event you are creating a delegate and passing it to the event source. The delegate holds a reference to the object to be called when the event is fired. That is the object reference goes like "source has a reference on target". If you throw the source away, the target doesn't care.

Since you already introduce the factory it should be the factory's job to keep the notifiers alive, i.e. by keeping them in a static list or more elaborate schemes of reusing notifiers etc.

As suggested in a comment, the observer / observable pattern may be of interest to you. The factory implements IObservable<T> , the consumer IObserver<T> . As long as you keep the observable alive, any referenced observers will be notified. If you add Rx-Extensions to the equation you get a rich set of methods to deal with Observables. They will e.g. usually allow to dispose of an observation, removing the reference that Observable has an Observer.


You could create a base class for MyNotifyingClass which is the type stored in the MyHandlingClass:

class BaseNotifyingClass // or maybe an interface type
{
  // put event in here
}

class MyNotifyingClass : public BaseNotifyingClass
{
  // as before, without event
}

class MyHandlingClass
{
  public MyHandlingClass (BaseNotifyingClass notifier)
  {
     m_notifier = notifier;
     m_notifier.Notify += HandleNotification;
  }
  // etc...
}

class SomeFactory
{
  public MyHandlingClass Create()
  { 
    var myNotifier = new MyNotifyingClass();
    var myHandler = new MyHandlingClass(myNotifier);

    return myHandler;
  }
  // etc...
}

This has the added benefit of encapsulating the link between the two classes within the classes themselves, and the factory becomes what the name suggests, a service for creating objects. This means that changing the way the two classes are linked does not require changing the factory class.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜