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);
    }
    // ...
}

一切正常,但我从 Visual Studio 收到以下警告:

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

不要同时使用isas。您只需要使用as并检查结果是否为 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 提供了一个专门构建的MessageCracker类,我确信它已被有效实现,将通用 FIX 消息“破解”为特定的强类型消息对象,这似乎正是您想要做的。这样做的好处不仅仅是(可能)提高了性能;代码将更简洁(更少的检查和强制转换,并且每个消息的处理代码将自然地移动到适当的处理程序)并且在面对无效消息时更加健壮。

编辑:看看 的来源MessageCracker,正如 John 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
QuickFix42.ExecutionReport executionReportMessage = message as QuickFix42.ExecutionReport;
if (executionReportMessage != null) 
{ 
  ProcessExecutionReport(executionReportMessage); 
} 
于 2010-10-11T10:15:26.167 回答
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 回答
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 回答
1
public void OnMessageReceived(QuickFix42.Message message)
{
    QuickFix42.ExecutionReport executionReport;
    QuickFix42.AllocationACK allocationAck;
    QuickFix42.OrderCancelReject orderCancelReject;

    if ((executionReport = message as QuickFix42.ExecutionReport) != null)
    {
        ProcessExecutionReport(executionReport);
    }
    else if ((allocationAck = message as QuickFix42.AllocationACK) != null)
    {
        ProcessAllocationAck(allocationAck);
    }
    else if ((orderCancelReject = message as QuickFix42.OrderCancelReject) != null)
    {
        ProcessOrderCancelReject(orderCancelReject);
    }
    // ...
}
于 2011-10-17T05:43:27.470 回答