2015-02-08 56 views
1

我想要做的就是爲我的遊戲我開發我有一個使用電報結構消息系統如下:是否可以使用類型變量來轉換對象的變量?

public struct Telegram 
{ 
    private int sender; 
    private int receiver; 
    public int Receiver 
    { 
     get 
     { return receiver; } 
    } 

    //Message of an enumerated messageToSend in Messages 
    private Message messageToSend; 
    public Message MessageToSend 
    { 
     get 
     { return messageToSend; } 
    } 

    //for delayed messages 
    private double dispatchTime; 
    public double DispatchTime 
    { 
     get 
     { return dispatchTime; } 
     set 
     { dispatchTime = value; } 
    } 

    //for any additional info 
    private object extraInfo; 
    public object ExtraInfo 
    { 
     get 
     { return extraInfo; } 
    } 

    public Telegram(double time, int otherSender, int otherReceiver, 
       Message otherMessage, object info = null) 
    { 
     dispatchTime = time; 
     sender = otherSender; 
     receiver = otherReceiver; 
     messageToSend = otherMessage; 
     extraInfo = info; 
    } 
} 

我希望能夠做的是,因爲額外信息是基於消息類型傳遞的,並且需要是對象,爲了方便不必使用各種額外的信息類型對一堆函數進行編碼,我希望獲取其裝入的對象的類型函數通過額外的信息變量。

我知道我可以用.getType()做到這一點,並將其存儲在Type變量中。

這裏有棘手的部分,我不知道我能做些什麼。我想要做的是使用該變量在收到電報的東西根據發送的消息類型處理它時轉換對象。這可能嗎?

不能使用通用的電報類,因爲它導致事情打破,當我只是試圖轉換我的消息代碼。這裏是其餘的相關代碼:

/*Telegrams are stored in a priority queue. Therefore the < and == 
    operators are overloaded so the PQ can sort the telegrams 
    by time priority. Times must be smaller than 
    SmallestDelay before two Telegrams are considered unique.*/ 
    public const double SmallestDelay = 0.25; 

    public static bool operator ==(Telegram t1, Telegram t2) 
    { 
     return (Math.Abs(t1.dispatchTime - t2.dispatchTime) < SmallestDelay) && 
     (t1.sender == t2.sender) && 
     (t1.receiver == t2.receiver) && 
     (t1.messageToSend == t2.messageToSend); 
    } 

    public static bool operator !=(Telegram t1, Telegram t2) 
    { 
     return (Math.Abs(t1.dispatchTime - t2.dispatchTime) > SmallestDelay) && 
     (t1.sender != t2.sender) && 
     (t1.receiver != t2.receiver) && 
     (t1.messageToSend != t2.messageToSend); 
    } 

    public static bool operator <(Telegram t1, Telegram t2) 
    { 
     if (t1 == t2) 
      return false; 
     else 
      return (t1.dispatchTime < t2.dispatchTime); 
    } 

    public static bool operator >(Telegram t1, Telegram t2) 
    { 
     if (t1 == t2) 
      return false; 
     else 
      return (t1.dispatchTime > t2.dispatchTime); 
    } 

sealed class MessageDispatcher 
{ 
    public const double sendMessageImmediately = 0.0; 
    public const int noAdditionalInfo = 0; 
    public const int senderIdIrrelevant = -1; 

    //a set is used as the container for the delayed messages 
    //because of the benefit of automatic sorting and avoidance 
    //of duplicates. Messages are sorted by their dispatch time. 
    private static SortedSet<Telegram> priorityQueue = new SortedSet<Telegram>(); 

    /// <summary> 
    /// this method is utilized by DispatchMessage or DispatchDelayedMessages. 
    /// This method calls the messageToSend handling member function of the receiving 
    /// entity, receiver, with the newly created telegram 
    /// </summary> 
    /// <param name="receiver"></param> 
    /// <param name="messageToSend"></param> 
    private static void Discharge(ref BaseEntityInfo receiver, ref Telegram message) 
    { 
     if (!receiver.HandleMessage(ref message)) 
     { 
      //telegram could not be handled 
     } 
    } 

    private MessageDispatcher() { } 

    public static readonly MessageDispatcher instance = new MessageDispatcher(); 

    /// <summary> 
    /// given a messageToSend, a receiver, a sender and any time delay, this function 
    /// routes the messageToSend to the correct entity (if no delay) or stores it 
    /// in the messageToSend queue to be dispatched at the correct time. Entities referenced 
    /// by iD. 
    /// </summary> 
    /// <param name="delay"></param> 
    /// <param name="sender"></param> 
    /// <param name="otherReceiver"></param> 
    /// <param name="messageToSend"></param> 
    /// <param name="additionalInfo"></param> 
    public static void DispatchMessage(double delay, int sender, 
          int otherReceiver, Message message, 
          object additionalInfo = null) 
    { 
     //get the reciever 
     BaseEntityInfo receiver = EntityMgr.entityManager.GetEntityFromID(otherReceiver); 

     //make sure the Receiver is valid 
     if (receiver == null) 
      return; 

     //create the telegram 
     Telegram telegram = new Telegram(0, sender, otherReceiver, message, additionalInfo); 

     //if there is no delay, route telegram immediately      
     if (delay <= 0.0) 
      //send the telegram to the recipient 
      Discharge(ref receiver, ref telegram); 
     //else calculate the time when the telegram should be dispatched 
     else 
     { 
      double CurrentTime = Clock.Current(); 
      telegram.DispatchTime = CurrentTime + delay; 
      //and put it in the queue 
      priorityQueue.Add(telegram); 
     } 
    } 

    /// <summary> 
    /// This function dispatches any telegrams with a timestamp that has 
    /// expired. Any dispatched telegrams are removed from the queue as it 
    /// sends out any delayed messages. This method is called each time through 
    /// the main game loop. 
    /// </summary> 
    public static void DispatchDelayedMessages() 
    { 
     double CurrentTime = Clock.Current(); 

     //now peek at the queue to see if any telegrams need dispatching. 
     //remove all telegrams from the front of the queue that have gone 
     //past their sell by date 
     while (!(priorityQueue.Count == 0) && 
       (priorityQueue.ElementAt(0).DispatchTime < CurrentTime) && 
       (priorityQueue.ElementAt(0).DispatchTime > 0)) 
     { 
      //read the telegram from the front of the queue 
      Telegram telegram = priorityQueue.ElementAt(0); 

      //find the recipient 
      BaseEntityInfo receiver = EntityMgr.entityManager.GetEntityFromID(telegram.Receiver); 

      //send the telegram to the recipient 
      Discharge(ref receiver, ref telegram); 

      //remove it from the queue 
      priorityQueue.Remove(priorityQueue.ElementAt(0)); 
     } 
    } 
} 
+5

你能解釋一下爲什麼你認爲'struct'在這裏是個好主意嗎? – spender 2015-02-08 18:11:52

+3

[「類和結構之間進行選擇」](https://msdn.microsoft.com/en-us/library/ms229017%28v=vs.110%29.aspx)表示如下:避免定義一個結構,除非該類型具有以下所有特徵:(a)它邏輯上表示一個單一的值,類似於原始類型(int,double等)。 (b)它具有小於16字節的實例大小。 (c)它是不可變的。 (d)不必頻繁地裝箱。 *根據我的估算,你在四項計數中都失敗了。* – spender 2015-02-08 18:15:11

+0

因爲我不需要電報作爲課程。 – 2015-02-08 18:16:00

回答

1

首先,why use struct in this case? C#中的結構與C++中的結構不同 - 在這種情況下,每次在方法中傳遞對象時,將複製對象,這可能是一種非常耗費內存的解決方案。

其次,儘量使用Generic方法,像這樣:

public Telegram<T>(double time, int otherSender, int otherReceiver, 
      Message otherMessage, T info = null) 
where T : class 
{ 
    dispatchTime = time; 
    sender = otherSender; 
    receiver = otherReceiver; 
    messageToSend = otherMessage; 
    // check for T here 
} 

如果你想澄清你想實現什麼,社區可以幫助你更好的辦法。

泛型方法的使用就像C++中的模板方法。唯一的問題是,如果你想有一個參數化的構造函數,你必須聲明generic class,像這樣:

public class Telegram<T> 
{ 
    T additionalInfo; 

    Telegram(double time, int otherSender, int otherReceiver, 
      Message otherMessage, T info = null) 
    where T : class 
+0

不知道,因爲我在C++中教過的結構,一直在試圖自學C#。也不會有一個通用的方法要求我每次我想發送不同類型的信息時創建一個方法? – 2015-02-08 18:35:25

+0

@ThomasMorse更新了答案。 – VMAtm 2015-02-08 19:09:58

+0

@ThomasMorse不,不需要其他方法 - 對於特定類型的其他信息可能只是一個新的邏輯。 – VMAtm 2015-02-08 19:16:45

0

可以使用Convert.ChangeType(object value, Type type)see MSDN然而,像評論說,你在這裏誤用一個結構爲你的對象是不是一成不變的,小的,或邏輯上代表一個值,我會建議考慮一個class,並可能在一個通用的class

public class Telegram 
{ 
    public Telegram(double time, int otherSender, int otherReceiver, 
      Message otherMessage, object info = null) 
    { 
     DispatchTime = time; 
     Sender = otherSender; 
     Receiver = otherReceiver; 
     MessageToSend = otherMessage; 
     ExtraInfo = info; 
    } 

    public int Reciever {get; private set;} 
    public Message MessageToSend {get; private set;} 
    public double DispatchTime {get; set;} 
    public object ExtraInfo {get; private set;} 
} 

或作爲一般:

public class Telegram<T> 
{ 
    public Telegram(double time, int otherSender, int otherReceiver, 
      Message otherMessage, T info = default(T)) 
    { 
     DispatchTime = time; 
     Sender = otherSender; 
     Receiver = otherReceiver; 
     MessageToSend = otherMessage; 
     ExtraInfo = info; 
    } 

    public int Reciever {get; private set;} 
    public Message MessageToSend {get; private set;} 
    public double DispatchTime {get; set;} 
    public T ExtraInfo {get; private set;} 
} 

泛型類型參數的優勢在於,你既可以很容易地知道是什麼類型(typeof(T)),你可以投的類型,而不必依賴你可以對T施加約束,如where T: class, new(),它說它必須是一個引用類型,它必須有一個默認的構造函數,或者你可以要求一個接口實現,讓你訪問它的成員。

要詳細說明,一般只會公開關於成員的類型信息,所以不需要將object轉換成int,它只是已經是int

例如:

var myTelegram = new Telegram(1235.3423, 42, 69, myMessageObj, 32); 
var extraInfo = myTelegram.ExtraInfo; 
var extraInfoType = extraInfo.GetType(); 
    //extraInfoType is int, and you don't have to unbox it. 

有關泛型的詳細信息,一個偉大的地方開始爲http://www.dotnetperls.com/generic - 那麼您可以在挖掘到MSDN或其他資源。

更新:

至於你剛纔添加什麼澄清,你仍然可以使用泛型,但你將不得不把一些類型的限制就可以了,或者你的SortedSet<T>將不得不Telegram<object>哪些呢限制一些事情。但是,不管你做什麼,最終有用的信息是,你可以在方法級別使用仿製藥,所以你不必總是聲明一個類爲通用的,例如:

public sealed class MessageDispatcher 
{ 
    public static void DispatchMessage<T>(double delay, int sender, 
          int otherReceiver, Message message, 
          T additionalInfo = default(T)) 
    ... 
} 

我做只是爲了可以肯定,複製您發佈並提出與仿製藥版本的代碼,所以這是可以做到的,但與仿製藥也有爲了得到它來編譯,因爲覆蓋GetHashCode()方法和Equals(obj other)方法(從System.Object繼承)你超載了運營商。

不過,如果你不能限制說類似IComparable<T>或其他一些界面,你會從寂寂類型的一些屬性中受益,那麼你不妨用對象去,然後用value as Type類型鑄造或Convert.ChangeType(Object obj, Type type)

public class Telegram<T> 
{ 
    public int Sender { get; private set; } 
    public int Receiver { get; private set; } 

    //Message of an enumerated messageToSend in Messages 
    public Message MessageToSend { get; private set; } 

    //for delayed messages 
    public double DispatchTime { get; set; } 

    //for any additional info 
    public T ExtraInfo { get; private set; } 

    public Telegram(double time, int otherSender, int otherReceiver, 
       Message otherMessage, T info = default(T)) 
    { 
     DispatchTime = time; 
     Sender = otherSender; 
     Receiver = otherReceiver; 
     MessageToSend = otherMessage; 
     ExtraInfo = info; 
    } 

    public override int GetHashCode() 
    { 
     return base.GetHashCode(); 
    } 

    public override bool Equals(object obj) 
    { 
     return base.Equals(obj); 
    } 

    /*Telegrams are stored in a priority queue. Therefore the < and == 
    operators are overloaded so the PQ can sort the telegrams 
    by time priority. Times must be smaller than 
    SmallestDelay before two Telegrams are considered unique.*/ 
    public const double SmallestDelay = 0.25; 

    public static bool operator ==(Telegram<T> t1, Telegram<T> t2) 
    { 
     return (Math.Abs(t1.DispatchTime - t2.DispatchTime) < SmallestDelay) && 
     (t1.Sender == t2.Sender) && 
     (t1.Receiver == t2.Receiver) && 
     (t1.MessageToSend == t2.MessageToSend); 
    } 

    public static bool operator !=(Telegram<T> t1, Telegram<T> t2) 
    { 
     return (Math.Abs(t1.DispatchTime - t2.DispatchTime) > SmallestDelay) && 
     (t1.Sender != t2.Sender) && 
     (t1.Receiver != t2.Receiver) && 
     (t1.MessageToSend != t2.MessageToSend); 
    } 

    public static bool operator <(Telegram<T> t1, Telegram<T> t2) 
    { 
     if (t1 == t2) 
      return false; 
     else 
      return (t1.DispatchTime < t2.DispatchTime); 
    } 

    public static bool operator >(Telegram<T> t1, Telegram<T> t2) 
    { 
     if (t1 == t2) 
      return false; 
     else 
      return (t1.DispatchTime > t2.DispatchTime); 
    } 
} 

public sealed class MessageDispatcher 
{ 
    public const double sendMessageImmediately = 0.0; 
    public const int noAdditionalInfo = 0; 
    public const int senderIdIrrelevant = -1; 

    //a set is used as the container for the delayed messages 
    //because of the benefit of automatic sorting and avoidance 
    //of duplicates. Messages are sorted by their dispatch time. 
    private static SortedSet<Telegram<object>> priorityQueue = new SortedSet<Telegram<object>>(); 

    /// <summary> 
    /// this method is utilized by DispatchMessage or DispatchDelayedMessages. 
    /// This method calls the messageToSend handling member function of the receiving 
    /// entity, receiver, with the newly created telegram 
    /// </summary> 
    /// <param name="receiver"></param> 
    /// <param name="messageToSend"></param> 
    private static void Discharge<T>(BaseEntityInfo receiver, Telegram<T> message) 
    { 
     if (!receiver.HandleMessage(message)) 
     { 
      //telegram could not be handled 
     } 
    } 

    private MessageDispatcher() { } 

    public static readonly MessageDispatcher instance = new MessageDispatcher(); 

    /// <summary> 
    /// given a messageToSend, a receiver, a sender and any time delay, this function 
    /// routes the messageToSend to the correct entity (if no delay) or stores it 
    /// in the messageToSend queue to be dispatched at the correct time. Entities referenced 
    /// by iD. 
    /// </summary> 
    public static void DispatchMessage<T>(double delay, int sender, 
          int otherReceiver, Message message, 
          T additionalInfo = default(T)) 
    { 
     //get the reciever 
     BaseEntityInfo receiver = EntityMgr.entityManager.GetEntityFromID(otherReceiver); 

     //make sure the Receiver is valid 
     if (receiver == null) 
      return; 

     //create the telegram 
     var telegram = new Telegram<object>(0, sender, otherReceiver, message, additionalInfo); 

     //if there is no delay, route telegram immediately      
     if (delay <= 0.0) 
      //send the telegram to the recipient 
      Discharge(receiver, telegram); 
     //else calculate the time when the telegram should be dispatched 
     else 
     { 
      double CurrentTime = Clock.Current(); 
      telegram.DispatchTime = CurrentTime + delay; 
      //and put it in the queue 
      priorityQueue.Add(telegram); 
     } 
    } 

    /// <summary> 
    /// This function dispatches any telegrams with a timestamp that has 
    /// expired. Any dispatched telegrams are removed from the queue as it 
    /// sends out any delayed messages. This method is called each time through 
    /// the main game loop. 
    /// </summary> 
    public static void DispatchDelayedMessages() 
    { 
     double CurrentTime = Clock.Current(); 

     //now peek at the queue to see if any telegrams need dispatching. 
     //remove all telegrams from the front of the queue that have gone 
     //past their sell by date 
     while (!(priorityQueue.Count == 0) && 
       (priorityQueue.ElementAt(0).DispatchTime < CurrentTime) && 
       (priorityQueue.ElementAt(0).DispatchTime > 0)) 
     { 
      //read the telegram from the front of the queue 
      var telegram = priorityQueue.ElementAt(0); 

      //find the recipient 
      BaseEntityInfo receiver = EntityMgr.entityManager.GetEntityFromID(telegram.Receiver); 

      //send the telegram to the recipient 
      Discharge(receiver, telegram); 

      //remove it from the queue 
      priorityQueue.Remove(priorityQueue.ElementAt(0)); 
     } 
    } 
} 
+0

使用通用類型的問題是,當我只需要一種類型的電報時,我會收到大量的電報副本,並且需要爲每種額外類型實現一個電報類我想要發送的信息可能在一百個左右。 – 2015-02-08 18:33:16

+0

你不需要實現多個實例,泛型在C#中是真正的泛型,與Java不同,一類'Telegram '可以在任何地方使用,無論'T'是什麼類型。即使在運行時。 – tophallen 2015-02-08 18:34:27

+0

好的,我不知道。那麼我怎麼稱呼那個功能呢?不熟悉泛型。 – 2015-02-08 18:38:52

0

我會建議使用Convert.ChangeType選項。在這種情況下,使用仿製藥不會增加多少好處,並因爲當你創建SortedSet<Telegram> 你就必須指定SortedSet<Telegram<T>>可以揹你到一個角落裏的MessageDispatcher類中,而T3可以是任何東西,如果我,如果我記得沒錯(指正錯了)擁有不同的Ts的集合將不起作用。

每個處理器需要知道的額外的信息,以及如何處理數據的「類型」,圍繞一個對象或基類,所以路過就足夠了。調度員不關心額外信息的類型或接收者是否可以實際處理額外的信息。當接收者處理一個電報時,它可以簡單地在額外的信息上調用GetType,將它傳遞給ChangeType方法,如果它成功轉換,那麼很好......如果不是,那麼處理這個轉換錯誤。

編輯1:你可以簡單地做一個MyRealType result = extraInfo as MyRealType,然後如果result是NULL,那麼你知道錯誤類型的額外信息已經過去的接收器。

相關問題