5


基本型のパラメータを受け取り、実際のパラメータ型に応じて前処理を行うメソッドがあります。
これが私のコードです:


public void OnMessageReceived(QuickFix42.Message message)
{
    if (message is QuickFix42.ExecutionReport)
    {
        ProcessExecutionReport(message as QuickFix42.ExecutionReport);
    }
    else if (message is QuickFix42.AllocationACK)
    {
        ProcessAllocationAck(message as QuickFix42.AllocationACK);
    }
    else if (message is QuickFix42.OrderCancelReject)
    {
        ProcessOrderCancelReject(message as QuickFix42.OrderCancelReject);
    }
    // ...
}

すべて正常に動作しますが、VisualStudioから次の警告が表示されます。

Warning 760 CA1800 : Microsoft.Performance : 'message', a parameter, is cast to type 'ExecutionReport' multiple times in method 'MessageProcessor.OnMessageReceived(Message)'. Cache the result of the 'as' operator or direct cast in order to eliminate the redundant isint instruction.

これらの冗長なキャストを回避するための最良の方法は何ですか?

4

7 に答える 7

11

isとの両方を使用しないでくださいasas結果がnullかどうかを使用して確認する必要があります:

QuickFix42.ExecutionReport execReport = message as QuickFix42.ExecutionReport
if (execReport != null)
{
  ProcessExecutionReport(execReport);
}
于 2010-10-11T10:14:49.880 に答える
7

コードの繰り返し構造を考えると、次の方法でクリーンアップできます。

public void OnMessageReceived(QuickFix42.Message message)
{
    ExecuteOnlyAs<QuickFix42.ExecutionReport>(message, ProcessExecutionReport);
    ExecuteOnlyAs<QuickFix42.AllocationACK>(message, ProcessAllocationAck);
    ExecuteOnlyAs<QuickFix42.OrderCancelReject>(message, ProcessOrderCancelReject);
}

private void ExecuteOnlyAs<T>(QuickFix42.Message message, Action<T> action)
{
    var t = message as T;
    if (t != null)
    {
        action(t);
    }
}

これは、型が互いに継承しないことを前提としています。ExecuteOnlyAsその場合は、成功を示すメッセージを返すように変更しbool、以前と同じように if ステートメントを実行する必要があります。

于 2010-10-11T10:26:37.917 に答える
5

他の人が投稿したように、単一のas後にnull-test を付けると非常に効率的です。ただし、これは QuickFix アプリのようです。QuickFix は、一般的な FIX メッセージを特定の厳密に型指定されたメッセージ オブジェクトに「クラック」するために、効率的に実装されていると確信している専用のMessageCrackerクラスを提供します。このようにする利点は、(おそらく) パフォーマンスの向上だけではありません。コードはよりクリーンになり (チェックとキャストが少なくなり、メッセージごとの処理コードが適切なハンドラーに自然に移動されます)、無効なメッセージに直面してもより堅牢になります。

編集: のソースを見ると、MessageCrackerJohn Zwinck によって促されたように、このクラスを使用するとおそらくパフォーマンスが向上するという考えに基づいています。

例: (クラスを から継承させるMessageCracker)

public void OnMessageReceived(QuickFix42.Message message, SessionID sessionID)
{
  crack (message, sessionID);
}

public override void onMessage(QuickFix42.ExecutionReport message, SessionID sessionID)
{
   ...
}

public override void onMessage(QuickFix42.OrderCancelReject message, SessionID sessionID)
{
   ...
}
于 2010-10-11T10:23:02.760 に答える
2

私の意見では、あなたはあなたのデザインに何か欠けているものがあると思います。通常、私は以前にこれに似たものを見たことがあり、それによってこれが発生する可能性があります。

public interface IResult
{
  // No members
}

public void DoSomething(IResult result)
{
  if (result is DoSomethingResult)
    ((DoSomethingResult)result).DoSomething();
  else if (result is DoSomethingElseResult)
    ((DoSomethingElseResult)result.DoSomethingElse();
}

コントラクトは操作を定義していないため、型キャストを実行してメリットを得る必要があります。これは正しいデザインではないと思います。コントラクト(インターフェースまたは抽象クラス)は、意図された操作を定義する必要があり、それを使用する方法を明確にする必要があります。上記の例は本質的に同じ問題でMessageあり、使用方法を定義していません...Message何らかの操作を強制するように変更する必要があります。

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

public class ExecutionReportMessage : Message
{
  public override void Process()
  {
    // Do your specific work here.
  }
}

これにより、実装が大幅に簡素化されます。

public void OnMessageReceived(QuickFix42.Message message)
{
    if (message == null)
      throw new ArgumentNullException("message");

    message.Process();
}

それははるかにクリーンで、よりテスト可能で、型キャストはありません。

于 2010-10-11T11:31:14.700 に答える
2
QuickFix42.ExecutionReport executionReportMessage = message as QuickFix42.ExecutionReport;
if (executionReportMessage != null) 
{ 
  ProcessExecutionReport(executionReportMessage); 
} 
于 2010-10-11T10:15:26.167 に答える
1

新しいメッセージが必要になるたびにこのコードを変更する必要があるため、上記のコードをリファクタリングできる方法はたくさんありますが、この要件を処理できるよく知られているデザインパターンがいくつかありますが、最初の開始では、以下のようなことを行うことができます。最善の方法ではありませんが、このコードをテストしていませんが、警告は削除されますが、そう思います。

public void OnMessageReceived(QuickFix42.Message message)  
{  
      QuickFix42.ExecutionReport ExecutionReportMessage = message as QuickFix42.ExecutionReport;
      QuickFix42.AllocationACK  AllocationACKMessage = message as QuickFix42.AllocationACK  ;
      QuickFix42.OrderCancelReject OrderCancelRejectMessage = message as QuickFix42.OrderCancelReject;

 if (ExecutionReportMessage !=null)  
{  
    ProcessExecutionReport(ExecutionReportMessage);  
}  
else if (AllocationACKMessage !=null)  
{  
    ProcessAllocationAck(AllocationACKMessage );  
}  
else if (OrderCancelRejectMessage !=null)  
{  
    ProcessOrderCancelReject(OrderCancelRejectMessage);  
}  
// ...  

}

于 2010-10-11T10:21:54.397 に答える