2017-10-17 3 views
2

J'ai une classe de base qui gère les messages reçus d'un flux. Maintenant, je veux vérifier si un nouveau message est reçu, lequel il est et en fonction de cela comment gérer ce message. Puis je pars de l'idée, le code serait beaucoup mieux à lire si je crée une classe de base pour tous les messages et beaucoup de classe dérivée pour les messages individuels. (J'ai environ 100 messages différents à gérer)Utilisation des propriétés en fonction du contenu d'une classe

Le problème ici: Nous ne pouvons pas convertir une classe de base en une classe dérivée (voir Convert base class to derived class) Ceci est logique total, et je comprends pourquoi il doit être comme ça. Mais je n'ai pas besoin d'une classe "entière", j'ai juste besoin d'une propriété nommée différemment, selon le message reçu, qui analyse les données de la classe de base. Mais je ne veux pas non plus une classe avec toutes les propriétés écrites comme public byte Message02_Value1 => Data[0]. Je voudrais utiliser cette syntaxe: MessageBaseClass.Message01.Value

Je pourrais aussi écrire du code alors qu'il est d'obtenir les données du flux

if (function == 1) new MessageBaseClass.Message01(); if (function == 2) new MessageBaseClass.Message02();

mais cela se sent comme un double travail ..

Donc, mon question est: Comment puis-je utiliser les propriétés qui analysent les données d'une classe de base, en fonction du type de contenu dans cette classe?

Pour clearify ce que je veux je l'ai écrit ce code (qui ne fait fonctionne pas)

class Program 
    { 
     static void Main(string[] args) 
     { 

      Msg[] messages = 
       { 
        new Msg { Function = 1, Data = new byte[] { 1, 2, 3, 4 } } , 
        new Msg { Function = 2, Data = new byte[] { 1, 2, 3, 4 } } 
       }; 

      foreach (Msg msg in messages) 
      { 
       switch (msg.Function) 
       { 
        case 1: 
         var Message1 = msg as Msg.Message01;//Error, is not able to convert --> Message1 == null 
         Console.WriteLine($"Serial: {Message1.Serial}"); 
         break; 
        case 2: 
         var Message2 = msg as Msg.Message02;//Error, is not able to convert --> Message2 == null 
         Console.WriteLine($"Value1: {Message2.Value1}" + 
          $"Value2: {Message2.Value2}" + 
          $"Value3: {Message2.Value3}"); 
         break; 
       } 
      } 
     } 

     class Msg 
     { 
      public byte Function { get; set; } 
      public byte[] Data { get; set; } 

      public class Message01 : Msg 
      { 
       public uint Serial => BitConverter.ToUInt32(Data, 0); 
      } 

      public class Message02 : Msg 
      { 
       public byte Value1 => Data[0]; 
       public byte Value2 => Data[1]; 
       public ushort Value3 => BitConverter.ToUInt16(Data, 2); 
      } 
     } 
    } 
+0

Vous êtes visant à avoir environ 100 classes dérivées dans votre code? Peut-être que c'est moi mais ça sonne comme s'il y avait un meilleur moyen que ça .. – Picnic8

+0

Je pense qu'il n'y a rien de mal avec le 'si (func ...' tu l'as fait, il suffit de le faire dans la fabrique de messages qui va convertir flux dans les instances de message et vous êtes bon imho. et puis vous pouvez utiliser l'héritage ou juste une interface pour vos classes de message qui aura quelque chose comme '.showMeData()' et vous êtes bon, de cette façon, votre usine est le seul endroit se soucier de la classe que vous instanciez – user3012759

+0

Il pourrait être mieux pour la maintenance de générer le code.Même si vous/nous venons avec un grand design, la génération du code permettra de réduire considérablement l'impact d'un changement de message –

Répondre

4

L'approche que vous essayez de prendre est fondamentalement mauvais, pour les mêmes raisons qu'il est faux de activer le type d'exécution de votre classe. Essentiellement, vous faites la même chose, en remplaçant un type avec son code numérique.

C# offre une très bonne option pour le traitement des sous-classes sans envoi du type explicitement: faire des surcharges pour les types individuels, message jeté à dynamic, et que C# appeler la surcharge pour vous:

void ProcessMessages(IEnumerable<Msg> messages) { 
    foreach (var m in messages) { 
     ProcessSingleMessage((dynamic)m); 
    } 
} 

void ProcessSingleMessage(Message1 m1) { 
    // Access properties of m1 as needed 
} 
void ProcessSingleMessage(Message2 m2) { 
    // Access properties of m2 as needed 
} 
... 
// Catch-all handler 
void ProcessSingleMessage(Msg m) { 
    throw new InvalidOperationException("Received a message of unknown type: "+m.GetType()); 
} 
+0

un autre mieux –

+1

@EhsanSajjad Il s'agit d'un problème de répartition multiple, il existe de nombreuses solutions dans les langages OO, dont aucune n'est idéale, que j'utilise depuis plusieurs années maintenant. Ne me cause aucun problème jusqu'ici. – dasblinkenlight