2010-10-11 22 views
5


Baz türünde bir parametre alan ve gerçek parametre türüne bağlı olarak bir miktar ön işleme gerçekleştiren bir yöntem var. İşte
benim kodudur:Birden çok kez dökümden kaçınmak


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

Her şey çalışıyor, ama Visual Studio aşağıdaki uyarıyı alıyorum:

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.

bu gereksiz atmalarını önlemek için en iyi yolu nedir?

cevap

11

Hem is hem de as'u kullanmayın.

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

Böyle yaparak,/else-ifadeleri ayırmak için değiştirdiyseniz çok fazla gereksiz dökümün yapılmasıyla sonuçlanabilir. Orijinal yapıyı koruyan, biraz değiştirilmiş bir versiyon yayınladım. –

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

Eh her zaman bu kod olan yeni mesaj gerektirecektir çünkü refactored edilebilir kod yukarıdaki yollardan yeri vardır değiştirilmesine: sonucu sıfır ise sadece as kullanmak ve kontrol etmek Bu gereksinimi karşılayabilecek bazı iyi bilinen Tasarım Desenleri vardır, ancak ilk başlangıç ​​için aşağıdaki gibi bir şeyler yapabilirsiniz, bu en iyi yol değildir, ancak bu kodu test etmemiş olmamıza rağmen uyarıyı kaldırır ama bence. Diğerleri gönderdiniz gibi

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

}

5

, bir null -test ardından tek as oldukça verimli olacaktır. Ancak, bunun bir QuickFix uygulaması gibi göründüğünü fark ediyorum. QuickFix, MessageCracker sınıfı, bir amaca uygun şekilde uygulandığından emin olduğumdan emin olmak için, 'a özgü 'a özgü güçlü yazılan mesaj nesnelerine 'çatlak' için 'çatlamak', tam olarak ne yapmak istediğinizi görünür. Bu şekilde yapmanın faydaları, (muhtemelen) geliştirilmiş performanstan daha fazlası olacaktır; kodu daha temiz olacak (daha az kontrol ve atılacak ve her bir mesajın kullanım kodu doğal olarak uygun işleyiciye taşınacaktır) ve geçersiz mesajlar karşısında daha sağlam olacaktır.

DÜZENLEME: John Zwinck tarafından istendiği gibi, MessageCracker kaynağına bir bakın, bu sınıfı kullanmanın muhtemelen daha iyi bir performansla sonuçlanacağı fikrine koyar.

Örnek: (MessageCracker adresinin sınıf devralma yapmak)

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) 
{ 
    ... 
} 
+0

"MessageCrackerclass, etkili bir şekilde uygulandığından emin olduğumu söylüyorsunuz." Hiç baktınız mı? Hiç etkili bir şekilde uygulanmadı - eğer ifadeler, diğeri birbiri ardına gelen dev bir yığın (bu yıllardır doğru ve bunu yazarken doğrudur). Bakınız: http://quickfix.svn.sourceforge.net/viewvc/quickfix/trunk/quickfix/src/.NET/FIX42_MessageCracker.cs?revision=2229&view=markup. Bu gerçekten utanç verici. En azından el yapımı hazırlanmış bir/else zinciri ile yalnızca önem verdiğiniz vakaları kontrol edebilirsiniz (en yaygın mesajlarınızın krakerin alt kısmında olup olmadığını düşünün). –

+0

@John Zwinck: Ayakta durdum. Haklısın, çok kötü, değil mi? – Ani

7

Bu şekilde temizlemek edebilirsiniz kod tekrarlayan yapı göz önüne alındığında: Bu tip olduğunu varsayalım

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

birbirinden miras kalmayın. Eğer yaparlarsa, bool'u başarı belirtmek için ExecuteOnlyAs'u değiştirmeniz ve if ifadelerinin daha önce olduğu gibi yapması gerekir.

2

Bence tasarımınızdan eksik bir şeyiniz olduğunu düşünüyorum.Genellikle Bunun olabileceğini sayede, daha önce buna benzer bir şey gördüm: sözleşme herhangi işlemleri tanımlamaz

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(); 
} 

olduğundan, ondan herhangi bir yarar elde etmek türü çevrim gerçekleştirmek için zorlar. Bunun doğru bir tasarım olduğunu düşünmüyorum. Bir sözleşme (bir arabirim veya soyut bir sınıf olsun) amaçlanan bir işlemi tanımlamalı ve bunun nasıl kullanılacağı açık olmalıdır. , Önüne aldığımızda

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

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

büyük ölçüde uygulamanızı kolaylaştırmak: Yukarıdaki örnek, bazı operasyon uygulamak Message değiştirmesi gerektiğini ... Message kullanılması gerektiği şeklini tanımlayan değil, temelde aynı konudur:

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

    message.Process(); 
} 
daha sınanabilir, daha temiz

ve hiçbir tip döküm.

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