4

依存性注入を使用して新しいアプリケーションを緩く結合することを初めて試みました。私の問題は、ステータス情報をユーザーに返す方法です。昔は、すべてのコードがGUIに詰め込まれていたため、非常に面倒で保守が困難な場合でも、非常に簡単でした。クラスの配置は次のようなものです(私のUMLスキルをチェックしないでください-それらは存在しません):

アプリケーションの概要

右側を取ると。AirportsInformationRepositoryはデータを保存するだけで、要求されたときにコントローラーがデータを利用できるようにします。最初に、Persistクラスを使用して情報を取得し、ユーザーのハードドライブから特定のフィルターに一致するファイルを取得します。デコンパイラーを使用して、ファイルから情報を抽出します。これはすべて正常に機能し、情報自体は必要に応じてGUIに到達します。

私の問題は、並行して、何が起こっているのかをユーザーに伝える方法です。これは、逆コンパイラで発生する可能性があります。たとえば、取得したファイルを逆コンパイルできない場合や、データが含まれていない場合などです。構成ファイルが嘘をついていて、いくつかのフォルダーが存在しない場合、Persistクラスで発生する可能性があります。致命的なエラーがない限り、このような問題によってプロセスが停止することはありません。

致命的なエラーが発生した場合は、すぐにユーザーに返信する必要があり、プロセス全体が停止します。そうしないと、プロセスを通じて警告が収集され、スキャンが完了したときに表示される可能性があります。

私はロギングに精通しており、アプリケーションには、未処理の例外やその他の障害がないかアプリケーションを監視するロガーがあります。これはディスクに書き込み、バグに対処するためにほとんどの場合と同じようにこれを使用します。正直なところ、ファイルが見つからない場合やユーザーが構成ファイルへの無効なパスを入力した場合でも、アプリに問題はないため、これをユーザーへのステータスレポートに使用したくありません。

私は考慮しました:

  • 各クラスにログを蓄積し、プロセスが完了した(または失敗した)ときにログをコンシューマーに返します。私はそれが本当に厄介だと思っています
  • イベントを使用しますが、コンシューマーがサブスクライブしていて、イベントがログと同じようにチェーンを通過している場合、それがはるかに優れているとは思いません。別の方法は、GUIを直接サブスクライブさせることだと思いますが、逆コンパイラーについては何も知らないはずです。
  • 静的クラスであるか、program.csでインスタンス化されるホームロールロガー
  • ある種のメッセージングフレームワーク-はっきりしていませんが、GUIが他のクラスについて何も知らなくてもサブスクライブできる中央のイベントハンドラーにかなり似ていると思います。

要約すると。「通常どおりのビジネス」ステータス情報を蓄積し、スキャンの最後にGUIに提供すると同時に、致命的な問題で停止できるようにするための最良の方法は何ですか。

これを読んでくれてありがとう。投稿の長さについてお詫び申し上げます。

編集 私はアプリがNET3.5を使用していると言ったはずです。エレガントな解決策を得るためにこれを変更しますが....

4

2 に答える 2

3

処理の典型的な「フロー」を扱う場合、おそらくマルチスレッド/並行処理フローでさえ、「メールスロット」/メッセージポンプが最善のアプローチです。メッセージを交換することで、アプリケーションの複数のレイヤーを簡単に調整できます。これには、エラーの報告、次のコマンドチェーンへの通知などが含まれます。Windowsメッセージではなく、次のような意味です。

public abstract class Message
{
   public abstract void Process();
} 

それで:

public class MessageQueue
{
   private Queue m_Queue;
   public void Post(Message msg) {....}
   public void Process() {.....}
}

次に、アプリのすべてのスレッド/処理層にMessageQueueを割り当て、次のようにメッセージを渡します。

    GUIMessageQueue.Post(
           new ErrorMessage("Internal async file reader ran out of buffer"));  

GUIスレッドに、GUIキューを読み取り、それをProcess()と呼ぶタイマーを配置します。これで、メッセージから派生した多くの作業項目を作成して、スレッド/論理層間で非常に簡単に調整できるさまざまなタスクを実行できます。また、メッセージには、関連するデータピースへの参照が含まれる場合があります。

public AirplaneLandedMessage:メッセージ{public Airplane Plane ......}

これが、超並列チェーン処理システムで使用する実際のコードです。

/// <summary>
/// Defines a base for items executable by WorkQueue
/// </summary>
public interface IWorkItem<TContext> where TContext : class
{
  /// <summary>
  /// Invoked on an item to perform actual work. 
  /// For example: repaint grid from changed data source, refresh file, send email etc... 
  /// </summary>
  void PerformWork(TContext context);

  /// <summary>
  /// Invoked after successfull work execution - when no exception happened
  /// </summary>
  void WorkSucceeded();

  /// <summary>
  /// Invoked when either work execution or work success method threw an exception and did not succeed
  /// </summary>
  /// <param name="workPerformed">When true indicates that PerformWork() worked without exception but exception happened later</param>
  void WorkFailed(bool workPerformed, Exception error);

}


/// <summary>
/// Defines contract for work queue that work items can be posted to
/// </summary>
public interface IWorkQueue<TContext> where TContext : class
{
  /// <summary>
  /// Posts work item into the queue in natural queue order (at the end of the queue)
  /// </summary>
  void PostItem(IWorkItem<TContext> work);

  long ProcessedSuccessCount{get;}
  long ProcessedFailureCount{get;}

  TContext Context { get; }
}
于 2012-12-27T17:29:22.073 に答える
1

まあ、致命的なエラーは簡単な部分です、それらは単に例外を介して処理されます。ワーカースレッドは、作業を続行できない問題が発生したときに例外をスローできます。その後、UIレイヤーに到達した時点で、例外をキャッチして、実際にはなくてもユーザーに適切なエラーメッセージを表示できます。アプリケーションをクラッシュさせます。さまざまなタイプの例外と例外メッセージを使用して、さまざまな問題がさまざまなUI応答をもたらすようにすることができます。

致命的でないステータスを示すことに関しては、そのためのIProgressインターフェースを使用することができます。UIレイヤーProgressでは、呼び出されたときに更新されるインスタンスを作成できます...新しいステータスで何でも。次に、インスタンスをワーカークラスに渡し、IProgress提供する情報があるときにインスタンスを起動できます。

4.5より前なので、このクラスを書き直すのは簡単です。

public interface IProgress<T>
{
    public void Report(T parameter);
}

public class Progress<T>:IProgress<T>
{
    public event Action<T> ProgressChanged;

    public Progress() { }
    public Progress(Action<T> action)
    {
        ProgressChanged += action;
    }

    void IProgress<T>.Report(T parameter)
    {
        ProgressChanged(parameter);
    }
}

注:実際のProgressクラスはイベントをUIスレッドにマーシャリングしますが、その部分は追加しなかったので、追加するか、イベントハンドラーで実行します。

于 2012-12-27T17:12:41.247 に答える