Frage

I have a method that does some stuff that takes a while and posts progress/status messages back. The method used to be the Main() static method in my console Program class. Later, I decided to move the functionality into a shared library assembly, so that the same functionality could be accessed by a new web api project, so a different user interface with different mechanisms for stdio.

What is a good design pattern to replace all my Console.Writeline() calls in the moved method?

I'm thinking along the lines of adding an observable collection (of strings) to store the messages and then getting any calling assemblies to subscribe to changes on the collection and implement their own ui mechanisms for displaying messages back to the user.

Is this reasonable or is this reinventing the wheel? Is there already a purpose built method in the framework to handle a scenario like this?

Edit:

Thanks to @astef, I implemented it like so:

public interface IMessageObserver
{
    void Notify(string message);
    void Notify(string format, params object[] args);
}

public class ConsoleMessageObserver : IMessageObserver
{
    public void Notify(string message)
    {
        Console.WriteLine(message);
    }

    public void Notify(string format, params object[] args)
    {
        Console.WriteLine(format, args);
    }
}

class Program
{
    static void Main()
    {
        Library.LongRunningMethod(new ConsoleMessageObserver());
    }
}

static class Library
{
    public static void LongRunningMethod(IMessageObserver observer)
    {
        observer.Notify("Some progress happened...");
    }
}
War es hilfreich?

Lösung

If you need someone to handle your progress messages, just define it:

public interface IProgressObserver
{
    void NotifyProgress(double done);
}

And use:

public void YourLongRunningMethod(IProgressObserver progressObserver)
{
    // ...

    progressObserver.NotifyProgress(1d);
}

Now you can be more specific on who will actually handle this messages. For example:

public class ConsoleProgressObserver : IProgressObserver
{
    public void NotifyProgress(double done)
    {
        Console.WriteLine("Progress: {0:0.00}%", done * 100);
    }
}

Here's one that was used in Windows 98 system ;)

public class StuckingProgressObserver : IProgressObserver
{
    private const double stucksAfter = 0.95;

    private readonly IProgressObserver wrapee;

    public StuckingProgressObserver(IProgressObserver wrapee)
    {
        this.wrapee = wrapee;
    }

    public void NotifyProgress(double done)
    {
        if (done < stucksAfter)
        {
            wrapee.NotifyProgress(done);
        }
    }
}

Andere Tipps

Using an event, like @astef suggests is a good idea, but their code isn't idiomatic C#. .NET supports delegates directly, so there is no need for a one method interface.

In C# we'd define a class ProgressChangedEventArgs : EventArgs and then add an EventHandler<ProgressChangedEventArgs> ProgressChanged to the class that generates the event.

In fact the framework already includes those in the System.ComponentModel namespace.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top