Работает ли Subject.Subscribe только в статическом экземпляре (или я что-то упустил)

Я возился с реактивными расширениями, и я столкнулся с проблемой, из-за которой я не могу понять, в чем причина.

Если я использую приложение режима консоли .NET 4, где все статично, как показано ниже:

using System;
using System.Reactive.Subjects;
using FakeDal;
using FakeDal.Entites;
using RxProducer;

namespace Runner
{
  class Program
  {
    private static readonly Subject<DaftFrog> _subject = new Subject<DaftFrog>();
    private static readonly Repository<DaftFrog> _frogRepo = new Repository<DaftFrog>();


    static void Main()
    {
      _subject.Subscribe(RespondToNewData);
    }

    private static void RespondToNewData(DaftFrog frog)
    {
      _frogRepo.Save(frog);
    }


  }
}

DaftFrog — это просто тестовый класс в моем поддельном классе DAL, это простой проект библиотеки классов .NET 4, класс DaftFrog — это простой poco с несколькими полями, метод dal.save просто выполняет console.WriteLine of поле в объекте DaftFrog.

Оба класса просто заменяют реальные вещи, как только я доберусь до работы кода RX.

В любом случае, вернемся к проблеме, так что приведенный выше код работает нормально, и если я сделаю несколько

_subject.OnNext(new DaftFrog());

звонки, поддельный класс dal, распечатывает то, что я ожидаю, и все работает нормально...

ОДНАКО >....

Если я затем перенесу этот код как есть в библиотеку классов, а затем обновлю эту библиотеку классов из моей «статической программы» следующим образом:

using System.Reactive.Subjects;
using FakeDal;
using FakeDal.Entites;

namespace RxProducer
{
  public class Producer
  {
    private readonly Subject<DaftFrog> _subject = new Subject<DaftFrog>();
    private readonly Repository<DaftFrog> _frogRepo = new Repository<DaftFrog>();

    private int _clock;

    public void Start()
    {
      _subject.Subscribe(RespondToNewData);
    }

    public void Stop()
    {
    }

    public void Tick()
    {
      if(_clock % 5 == 0)
      {
        DaftFrog data = new DaftFrog();
        _subject.OnNext(data);
      }
      _clock++;

    }

    private void RespondToNewData(DaftFrog frog)
    {
      _frogRepo.Save(frog);
    }
  }
}

А затем использовать этот класс в моей программе

using System;
using RxProducer;

namespace Runner
{
  class Program
  {
    private static readonly Producer _myProducer = new Producer();

    static void Main()
    {
      _myProducer.Start();

      while(!line.Contains("quit"))
      {
        _myProducer.Tick();
        line = Console.ReadLine();
      }

      _myProducer.Stop();
    }

  }
}

Тогда мой проект не скомпилируется.

В частности, он терпит неудачу в строке:

_subject.Subscribe(RespondToNewData);

в библиотеке классов RxProducer, что более важно, ошибка, которую возвращает компилятор, также не имеет большого смысла:

Error   1   The best overloaded method match for 'System.Reactive.Subjects.Subject<FakeDal.Entites.DaftFrog>.Subscribe(System.IObserver<FakeDal.Entites.DaftFrog>)' has some invalid arguments  H:\programming\rxtesting\RxProducer\Producer.cs 17  7   RxProducer

Error   2   Argument 1: cannot convert from 'method group' to 'System.IObserver<FakeDal.Entites.DaftFrog>'  H:\programming\rxtesting\RxProducer\Producer.cs 17  26  RxProducer

Сначала я подумал, что это могла быть статика, поэтому я сделал все в библиотеке классов статическими, и это не имело никакого значения.

Я действительно мало что делал с Rx до сих пор, но я работаю с C # и VS 99% времени, поэтому я знаю, что ошибка говорит мне, что он не может преобразовать тип некоторого описания, я просто не не понимаю, почему мне это говорят, особенно когда код отлично работает в статической программе, но не в библиотеке классов.

Шоути

ОБНОВИТЬ

Во-вторых, я просто знаю, что будут те, кто будет настаивать на том, чтобы я разместил определения fakedal и daft frog, хотя ИМХО они не потребуются, но чтобы усмирить полчища претендентов, которые будут спрашивать, вот они :-)

using System;

namespace FakeDal
{
  public class Repository<T>
  {
    public void Save(T entity)
    {
      Console.WriteLine("Here we write T to the database....");
    }

  }
}

namespace FakeDal.Entites
{
  public class DaftFrog
  {
    public int Id { get; set; }
    public string Name { get; set; }
    public bool IsTotalyDaft { get; set; }
  }
}

person shawty    schedule 07.04.2013    source источник


Ответы (2)


Включите using System; в файл, где у вас есть Producer, это поможет преобразовать RespondToNewData в IObserver<T>.

person outcoldman    schedule 07.04.2013
comment
И победитель ..... это полностью исправило ..... есть шанс, что вы можете расширить свой ответ, мне любопытно, почему это так :-) Обычно, когда мне нужно добавить сборку в мой использует предложение, R# скажет мне, какое именно, но в этом случае у R# не было ни подсказки, ни каких-либо предложений. - person shawty; 08.04.2013
comment
между прочим, это просто ударило меня по голове :-) это всегда простые вещи... 30+ лет в этой игре, и это все еще современный эквивалент пропавшего или (это меня сбивает с толку :-) - person shawty; 08.04.2013
comment
Вы используете метод Subscribe с параметром Action<T>, который определен в пространстве имен System. Компилятор умен и знает, как преобразовать делегат/метод в Action<T> (Разница между неявным и явным созданием делегата), но когда вы не указываете System, он просто не знает, во что он может его преобразовать. Я так понимаю это, но я никогда не пытался найти первопричину этой проблемы, может быть, я не совсем прав в этом. - person outcoldman; 08.04.2013
comment
хорошо, это работает для меня, и у меня нет времени ходить на охоту :-) PS: вы только что исправили довольно большую проблему, которая заставила меня почесать голову над тем, что я пишу для редизайна веб-сайта lidnug.org - person shawty; 08.04.2013
comment
Просто комментарий; добавление оператора using не скрывает RespondToNewData в IObservable‹T›, оно позволяет разрешение метода Extension, который принимает и Action‹T›, который сопоставляется с делегатом/методом RespondToNewData. - person Lee Campbell; 08.04.2013

Похоже, что у компилятора возникли проблемы с определением действия...возможно, отсутствует оператор использования для соответствующего метода расширения. В качестве альтернативы попробуйте один из следующих способов:

_subject.Subscribe ((Action<DaftFrog>) RespondToData);

Or:

var obs = Observer.Create ( I forget the overload );
_subject.Subscribe( obs);
person JerKimball    schedule 07.04.2013
comment
Попробуйте 1: изменить на - _subject.Subscribe((Action)RespondToNewData); привело к изменению ошибки на - Ожидался метод с подписью 'void RespondToNewData()', я заметил, что была версия универсального типа, когда я печатал, поэтому просто попробую, ваше предложение Observer... - person shawty; 08.04.2013
comment
Никогда не достиг попытки 2 для тех, кому интересно, решил это выше :-) - person shawty; 08.04.2013
comment
Я предполагаю, что вы на самом деле имели в виду _subject.Subscribe ((Action‹DaftFrog›) RespondToData); Это приведет к сбою компиляции, но, надеюсь, R# предложит импорт оператора using, похожего на приведенное выше решение. Оба являются в значительной степени правильным ответом. :-) - person Lee Campbell; 08.04.2013
comment
@leecampbell хех - да, моя точность значительно снижается, когда я отвечаю с телефона :) Кроме того, не буду придираться, но в моих первых предложениях, вероятно, отсутствует оператор использования, хотя и по неправильной причине. - person JerKimball; 08.04.2013
comment
Впечатляет, что вы отвечаете с телефона. Хороший! Живущий в будущем человек. - person Lee Campbell; 09.04.2013
comment
@LeeCampbell Хотел бы я знать what bloody key the back tick was на клавиатуре Swype. :( - person JerKimball; 09.04.2013