我有一个接收基本类型参数的方法,并根据实际参数类型执行一些预处理
这是我的代码:
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.
避免这些多余演员的最佳方法是什么?
答案 0 :(得分:11)
不要同时使用is
和as
。您只需使用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);
}
// ...
}