避免多次铸造

时间:2010-10-11 10:12:07

标签: c# performance casting quickfix


我有一个接收基本类型参​​数的方法,并根据实际参数类型执行一些预处理 这是我的代码:


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.

避免这些多余演员的最佳方法是什么?

7 个答案:

答案 0 :(得分:11)

不要同时使用isas。您只需使用as并检查结果是否为null:

QuickFix42.ExecutionReport execReport = message as QuickFix42.ExecutionReport
if (execReport != null)
{
  ProcessExecutionReport(execReport);
}

答案 1 :(得分: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语句。

答案 2 :(得分:5)

正如其他人发布的那样,单个as后跟null - 测试将非常有效。 我注意到,这似乎是一个QuickFix应用程序。 QuickFix提供了一个专门构建的MessageCracker类,我确信它是有效实现的,将“通用FIX消息”破解为特定的强类型消息对象,看来它正是你想要做的。这样做的好处不仅仅是(可能)提高了性能; 代码更清晰(更少的检查和转换,并且每个消息处理代码将自然地移动到适当的位置)处理器)并且在无效消息面前更加健壮。

编辑:根据John Zwinck的提示,查看MessageCracker的来源,认为使用此类可能会带来更好的性能。

示例:(使您的类继承自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)
{
   ...
}

答案 3 :(得分:2)

QuickFix42.ExecutionReport executionReportMessage = message as QuickFix42.ExecutionReport;
if (executionReportMessage != null) 
{ 
  ProcessExecutionReport(executionReportMessage); 
} 

答案 4 :(得分: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();
}

它更清洁,更可测试,并且没有类型铸造。

答案 5 :(得分: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);  
}  
// ...  

}

答案 6 :(得分: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);
    }
    // ...
}