2013-07-18 37 views
2

我有20個左右的事件類,都從EventDto繼承。這些子類都被序列化/反序列化(使用DataContractJsonSerializer,與每個子類被添加爲[KnownType(typeof運算(subclasstype))]屬性),則反序列化方法是這樣的:如何更改父類引用的子類以獲得子類的引用類型?

private EventDto DeserializeMessage(byte[] body) 
    { 
     var stream = new MemoryStream(body); 
     var serializer = new DataContractJsonSerializer(typeof(EventDto)); 

     var eventDto = (EventDto)serializer.ReadObject(stream); 

     return eventDto; 
    } 

反序列化事件之後,我需要根據其類型來處理它。所以,我有:

public void ProcessMessage(byte[] serializedEvent) 
    { 
     //Deserialize 
     var eventDto = DeserializeMessage(serializedEvent); 

     //Process 
     Process(eventDto); 
    } 

public void Process(EventDto eventDto) 
    { 
     //Do nothing 
    } 

    public void Process(EventDtoSubclass1 eventDto) 
    { 
     //Do something 
    } 

    public void Process(EventDtoSubclass2 eventDto) 
    { 
     //Do something different 
    } 

的問題是,在eventDto ProcessMessage的()具有EventDto的引用類型,所謂的進程()方法始終是相同的。我需要能夠區分EventDto的不同子類並調用適當的方法。

有沒有什麼辦法可以將EventMessage()中EventDto的類型從EventDto更改爲它的實際派生類型(比如EventDtoSubclass2)?

回答

1

有什麼辦法來改變eventDto的從EventDto ProcessMessage的()類型的實際派生類型(比如,EventDtoSubclass2的)?

不,你要麼提前知道類型(並且可以將其轉換或用作泛型類型參數或其他類型),或者必須在事實和分支之後檢測它。既然看起來你不知道你會得到什麼,那麼你需要檢測它並在其上分支(並且我的意思是使用is/asGetType/typeof或任何你最喜歡的檢查方法) 。

作爲一種替代方案,如果您可以更改您的EventDto派生類,那麼您可以將虛擬Process函數添加到基類中,並在每個派生類中執行正確的覆蓋版本。儘管如此,這取決於Process實際執行的操作。

編輯:由於I4V說,它不會工作,我打算在這裏放一個完整的程序,顯示我的選擇是什麼意思。就像我多次說過的,除非我們知道流程需要做什麼,否則我們不知道這是否真的可以用於OP。但它原則上工作。

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using System.Runtime.Serialization; 
using System.Runtime.Serialization.Json; 
using System.Text; 
using System.Threading.Tasks; 

namespace SOTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Program program = new Program(); 

      EventDtoA a = new EventDtoA() { AProperty = 0, BaseProperty = -1 }; 
      EventDtoB b = new EventDtoB() { BProperty = 1, BaseProperty = -1 }; 
      EventDtoC c = new EventDtoC() { CProperty = 2, BaseProperty = -1 }; 

      var aBytes = program.SerializeMessage(a); 
      var bBytes = program.SerializeMessage(b); 
      var cBytes = program.SerializeMessage(c); 

      var aString = System.Text.Encoding.UTF8.GetString(aBytes); 

      EventDto aNew = program.DeserializeMessage(aBytes); 
      EventDto bNew = program.DeserializeMessage(bBytes); 
      EventDto cNew = program.DeserializeMessage(cBytes); 

      aNew.Process(); 
      bNew.Process(); 
      cNew.Process(); 

      Console.ReadKey(); 
     } 

     private byte[] SerializeMessage(EventDto eventDto) 
     { 
      var stream = new MemoryStream(); 
      var serializer = new DataContractJsonSerializer(typeof(EventDto)); 
      serializer.WriteObject(stream, eventDto); 
      var tempBytes = new Byte[stream.Length]; 
      Array.Copy(stream.GetBuffer(), tempBytes, stream.Length); 
      return tempBytes; 
     } 

     private EventDto DeserializeMessage(byte[] body) 
     { 
      var stream = new MemoryStream(body); 
      var serializer = new DataContractJsonSerializer(typeof(EventDto)); 

      var eventDto = (EventDto)serializer.ReadObject(stream); 

      return eventDto; 
     } 

     public void ProcessMessage(byte[] serializedEvent) 
     { 
      //Deserialize 
      var eventDto = DeserializeMessage(serializedEvent); 

      //Process 
      eventDto.Process(); 
     } 


    } 

    [KnownType(typeof(EventDtoA))] 
    [KnownType(typeof(EventDtoB))] 
    [KnownType(typeof(EventDtoC))] 
    public class EventDto 
    { 
     public virtual void Process() 
     { 
      Console.WriteLine("From EventDto Base Class"); 
     } 

     public int BaseProperty { get; set; } 
    } 

    public class EventDtoA : EventDto 
    { 
     public override void Process() 
     { 
      Console.WriteLine("From EventDto A"); 
     } 

     public int AProperty { get; set; } 
    } 

    public class EventDtoB : EventDto 
    { 
     public override void Process() 
     { 
      Console.WriteLine("From EventDto B"); 
     } 

     public int BProperty { get; set; } 
    } 

    public class EventDtoC : EventDto 
    { 
     public override void Process() 
     { 
      Console.WriteLine("From EventDto C"); 
     } 

     public int CProperty { get; set; } 
    } 
} 

輸出:

From EventDto A 
From EventDto B 
From EventDto C 
+0

添加* *虛擬**處理方法,即 – Igor

+0

爲真。我加了一點解釋。 – Tim

+0

一切都很好,直到*替代*。 ** - 1 **(如果您能展示它的工作原理,我準備刪除-1) – I4V

1

最簡單的方法是使用is操作。

public void Process(EventDto eventDto) 
{ 
    //Do nothing 
    if (eventDto is EventDtoSubclass1) 
    { 
     // do something 
    } 
    else if (eventDto is EventDtoSubclass2) 
    { 
     // do something else 
    } 
} 
0

不知道你的代碼太多,是否有機會從架構的角度稍微修改一些東西?

在我看來,您可以使用命令模式的變體,並讓eventDTO對象負責自己的處理。

public interface IEventDTO{ 
    void Process(); 
} 

public class EventDTO1 : IEventDTO{ 
    public void Process(){ 
     //Glorious codde! 
    } 
} 

public class EventDTO2 : IEventDTO{ 
    public void Process(){ 
     //More glorious code!! 
    } 
} 

然後你可以有一個處理器,不需要關心處理所有不同的EventDTO的實現細節。將來,如果您需要添加更多EventDTO,處理器將不受任何更改影響。

public class Processor{ 
    public void Process(IEventDTO eventDTO){ 
      eventDTO.Process(); 
    } 
} 

這是寫在飛,所以原諒任何錯誤。也請原諒我的一部分的任何天真的到來了此基礎上進行很少的洞察到你的應用程序,它不適合該法案:)

編輯

我可能是有點累了這裏。如果你不希望的方法連接到一個DTO,這是完全可以理解的,我們可以創建一個IEventProcessor界面,並使用一個工廠來創建實現類型的實例,並使用這些處理:

public IEventProcessor GetEventProcessor(IEventDTO eventDTO){ 
     if(eventDTO is EventDTO1) 
      return new EventProcessor1(); 

     if(eventDTO is EvenetDTO2) 
      return new EventProcessor2(); 
}