2010-02-04 10 views
12

Digamos, tenemos una clase:¿Cuál es una buena forma de crear un IObservable para un método?

public class Foo 
{ 
    public string Do(int param) 
    { 
    } 
} 

Me gustaría crear un observable de los valores que se están produciendo por hacer método. Una forma de hacerlo sería crear un evento al que se llama desde Hacer y usar Observable.FromEvent para crear el evento. Pero de alguna manera no me siento bien con la creación de un evento solo por el bien de la tarea. Hay una mejor manera de hacerlo?

Respuesta

5

respuesta de Matt me hizo pensar en esto:

public class Foo 
{ 
    private readonly Subject<string> _doValues = new Subject<string>(); 

    public IObservable<string> DoValues { get { return _doValues; } } 

    public string Do(int param) 
    { 
     var ret = (param * 2).ToString(); 
     _doValues.OnNext(ret); 
     return ret; 
    } 
} 


var foo = new Foo(); 
foo.DoValues.Subscribe(Console.WriteLine); 
foo.Do(2); 
+1

Si esto es lo que realmente está buscando, al menos debe proteger su estado interno cambiando una línea a public IObservable DoValues ​​{get {return _doValues.AsObservable(); }}. Esto evitará que los consumidores vuelvan a colocar su IObservable en un objeto y luego en sus propios valores. :( –

1

Supongo que controlas la clase Foo, ya que estás hablando de agregarle un evento como una opción. Como usted es propietario de la clase, ¿hay alguna razón por la que no pueda definir su propia implementación IObservable para el método Do?

public class Foo 
{ 
    DoObservable _doValues = new DoObservable(); 

    public IObservable<String> DoValues 
    { 
     return _doValues; 
    } 

    public string Do(int param) 
    { 
     string result; 
     // whatever 
     _doValues.Notify(result); 
    } 
} 

public class DoObservable : IObservable<String> 
{ 
    List<IObserver<String>> _observers = new List<IObserver<String>>(); 

    public void Notify(string s) 
    { 
     foreach (var obs in _observers) obs.OnNext(s); 
    } 

    public IObserver<String> Subscribe(IObserver<String> observer) 
    { 
     _observers.Add(observer); 
     return observer; 
    } 
} 

Su clase tiene ahora una propiedad Observable<String> que proporciona una forma de suscribirse a los valores devueltos por el método Do:

public class StringWriter : IObserver<String> 
{ 
    public void OnNext(string value) 
    { 
     Console.WriteLine("Do returned " + value); 
    } 

    // and the other IObserver<String> methods 
} 

var subscriber = myFooInstance.DoValues.Subscribe(new StringWriter()); 
// from now on, anytime myFooInstance.Do() is called, the value it 
// returns will be written to the console by the StringWriter observer. 

no he incursionado demasiado en el marco reactiva, pero piensa que esto es parecido a cómo harías esto.

+0

Puede hacer que su clase DoObserver sea una clase interna (anidada) de la clase Foo, también, para mantenerla como un sistema cerrado. –

+0

También vea http://stackoverflow.com/questions/1768974/implementing-iobservablet-from-scratch, que tiene una implementación más completa que incluye la posibilidad de cancelar la suscripción a través de IDisposable. –

+0

Su DoObservable es solo Asunto , no es necesario reinventar la rueda –

-2

me gustaría ver el modelo EventAggregator. Hay un excelente artículo con código de muestra que muestra una implementación con StructureMap.

http://www.codeproject.com/KB/architecture/event_aggregator.aspx

+0

Mi pregunta fue específicamente sobre cómo lograr la tarea de manera más eficiente utilizando las extensiones RX. El enlace que proporcionó no está relacionado con RX. –

+0

Disculpe la confusión aquí, pero la pregunta es "¿Cuál es una buena forma de crear un IObservable para un método?". ¿Dónde dice algo acerca de las extensiones RX? EventAggregator es una forma desacoplada de lograr el patrón de observador. Todavía vale la pena mirar en mi opinión. –

+0

Hay un contexto que apunta a RX: la etiqueta, la referencia a una solución existente de usar Observable.FromEvent. De todos modos, a partir de ahora, el único IObservable "real" es el que proviene del espacio de nombres System.Reactive. –

1

Generalmente se quiere evitar el uso de los sujetos. En mi experiencia, es una señal de que estás haciendo algo mal. Observable.Create o quizás Generate son normalmente mejores ajustes.

Me gustaría ver lo que realmente está tratando de hacer para ver si podemos proporcionar una mejor respuesta. Lee

+0

No estoy de acuerdo, Observable.Create no impone la semántica de Rx, tiene que hacerlo usted mismo: es más fácil usar temas incluso si es menos Funcionalmente correcto ™. Crear es bueno cuando lo necesita, pero a menudo es excesivo. –

+1

El sujeto es un "puente" entre mundos funcionales y orientados a objetos proporcionados por RX. Entonces, a menos que su código sea 100% funcional, los sujetos son bastante útiles. –

+0

Estoy de acuerdo en desacuerdo. Después de haber usado Rx durante 2 años en un proyecto comercial con un grupo de chicos inteligentes, todos llegamos a la conclusión de que los temas son un olor a código, no siempre incorrecto, pero generalmente un punto de discusión en una revisión del código. También es una pena que la gente esté alentando al @Sergey y no señale los problemas con su código (específicamente .AsObservable()). Solo tratando de ayudar. –

0

Observable.Generate resuelve su problema, aunque no necesita utilizar la condición y continuar para su muestra. Esto sólo crea y continuamente objeto y devuelve el resultado de la llamada a DoIt():

Observable.Generate (
    new Foo(), 
    item => true, // in your example, this never terminates 
    item => item, // we don't actually do any state transitions 
    item => { return item.DoIt(); } // This is where we emit our value 
); 

En la práctica, a menudo no desea realizar un seguimiento algún estado y tener alguna condición de terminación. Generar lo hace fácil.

Cuestiones relacionadas