2013-08-02 2 views
2

Я пытаюсь использовать функцию ExcelAsyncUtil.Observe. Я сделал следующий код, который показывает текущие часы в Excel. Он отлично работает, но я не уверен, что делаю. Два вопроса:ExcelAsyncUtil.Observe - создать рабочие часы в Excel

  1. Должен ли я добавлять функции для observer.OnCompleted() и observer.OnError()? Что делают эти звонки?
  2. Что делать в классе IDisposible? Почему он там?

Вот мой пример кода:

[ExcelFunction] 
    public static object MyExcelTicker() 
    { 
     return ExcelAsyncUtil.Observe("MyExcelTicker", new object[] { }, TickerFunction()); 
    } 

    public static ExcelObservableSource TickerFunction() 
    { 
     ExcelObservableSource source = new ExcelObservableSource(() => new TickerObservable()); 
     return source; 
    } 

    public class TickerObservable : IExcelObservable 
    { 
     public IDisposable Subscribe(IExcelObserver observer) 
     { 
      var timer = new System.Timers.Timer(); 
      timer.Interval = 1000; 
      timer.Elapsed += (s, e) => observer.OnNext(DateTime.Now.ToString()); 
      timer.Start();  

      // What about observer.OnCompleted() and observer.OnError()? 
      return new TickerDisposable(); 
     } 
    } 

    public class TickerDisposable : IDisposable 
    { 
     public void Dispose() 
     { 
      // What to do here? 
     } 
    } 

ответ

1

интерфейс IExcelObserver соответствует семантику интерфейса IObserver из библиотеки Реактивные Extensions (http://msdn.microsoft.com/en-us/library/dd783449.aspx).

функции Вы можете вызвать OnNext ноль или более раз, а затем вызвать OnError, если произошла ошибка или OnCompleted не будет, если будет поднят никаких дальнейших событий. Excel-DNA будет обрабатывать OnError, поскольку это будет исключение, созданное обычным UDF, и вернет #VALUE в ячейку или обработает исключение через зарегистрированный UnhandledExceptionHandler. OnCompleted не так полезен в контексте Excel - он просто указывает, что никакие дополнительные значения не будут повышены.

Для вашего примера ошибка не кажется проблемой, и нет конца потоку событий, поэтому вам не нужно называть OnError или OnCompleted.

Инфраструктура Excel-DNA будет вызывать IDisposable.Dispose, когда наблюдаемое больше не подключается к формуле ячейки. Например, если формула с вызовом MyExcelTicker() удаляется из ячейки. Вы можете использовать это как уведомление для очистки любых внутренних ресурсов или игнорировать уведомление, если вас это не интересует.

4

Прошло некоторое время, и по крайней мере одна вещь по-прежнему не покрыта, поэтому позвольте мне добавить к тому, что сказал Говерт.

Вы спросили:

public class TickerDisposable : IDisposable 
{ 
    public void Dispose() 
    { 
     // What to do here? 
    } 
} 

Давайте подведем итог:

Для каждого нового абонента к вашей тактовой линеечке, Подписаться будет называться на TickerObservable. Поэтому для каждого абонента ваш код создаст новый System.Timers.Timer и новый обработчик событий timer.Elapsed - чтобы получить ваш предполагаемый эффект. И это на самом деле все то, что вам нужно, чтобы получить эффект.

Однако вы также должны вернуть IDisposable, поэтому вы создали фиктивный TickerDisposable исключительно для этой цели, и вы не знаете, для чего он предназначен.

Ответ:

IDisposable, что библиотека требует, чтобы вернуться из Subscribe есть только позволит вам после очистки вашего блеска перестает светить. Таймеры - это «системная вещь». Создав их и запустив, они запустите. Через час они не могут быть GC'ed, потому что они должны быть бежать, пока вы их не остановите.Разумеется, вы + = 'ed обработчик событий, наблюдатель (если слабая ссылка) может быть уже мертв, но ваш таймер не знает! Вы должны остановить его в какой-то момент.

Следовательно, шаблон, связанный с IDisposable, заимствованный из RX: любой тяжелый или долгоживущий, который вы выделяете, резервируете, создаете и т. Д. В методе Subscribe, помещайте в него примечание об этом (ваш!) IDisposable. Затем, когда наблюдатель отменит подписку, ваш IDisposable также будет очищен, а ваш пользовательский метод Dispose будет запущен, который сможет просматривать содержимое вашего IDiposable и .. очистить мусор, или, скорее, разблокировать его, поэтому GC может их смыть.

Завершение ваш пример:

public class TickerObservable : IExcelObservable 
{ 
    public IDisposable Subscribe(IExcelObserver observer) 
    { 
     var timer = new System.Timers.Timer(); 
     timer.Interval = 1000; 
     timer.Elapsed += (s, e) => observer.OnNext(DateTime.Now.ToString()); 
     timer.Start();  

     return new TickerDisposable(timer); 
    } 
} 

public class TickerDisposable : IDisposable 
{ 
    private Timer ticky; 
    public TickerDisposable(Timer timer) 
    { 
     ticky = timer; 
    } 

    public void Dispose() 
    { 
     if(ticky != null) 
      ticky.Dispose(); // or Stop, or etc.. 
    } 
} 

Приведенный выше пример является фактически наиболее очевидным использование возвращенного IDisposable. Однако вы можете использовать его для любого регистрационно-регистрационного уведомления. Например, один общий таймер, он может выглядеть следующим образом:

public class TickerObservable : IExcelObservable 
{ 
    private static Timer timer = ..... ; // assume it is up & running & shared 

    public IDisposable Subscribe(IExcelObserver observer) 
    { 
     ElapsedEventHander hd = (s, e) => observer.OnNext(DateTime.Now.ToString()); 
     timer.Elapsed += hd; 

     return new TickerDisposable(timer, hd); 
    } 
} 

public class TickerDisposable : IDisposable 
{ 
    private Timer ticky; 
    private ElapsedEventHander handler; 

    public TickerDisposable(Timer timer, ElapsedEventHander hd) 
    { 
     ticky = timer; 
     handler = hd; 
    } 

    public void Dispose() 
    { 
     if(ticky != null && handler != null) 
      ticky.Elapsed -= handler; 
    } 
} 

И теперь вы совершенно уверены, что никакие мертвые-обработчики не задерживаясь на долгоживущих-разделяемой таймера. (конечно, очистка таймера здесь отсутствует, но это еще одна вещь ..). Возможно, у вас уже есть идея, так что получайте удовольствие!