【问题标题】:Using properties depending of the content of a class根据类的内容使用属性
【发布时间】:2018-03-29 07:19:23
【问题描述】:

我有一个处理从流中接收到的消息的基类。现在我想检查是否收到了一条新消息,它是哪条消息以及如何处理这条消息。

然后我提出这个想法,如果我为所有消息创建一个基类并为单个消息创建许多派生类,则代码会更好阅读。 (我有大约 100 条不同的消息要处理)

这里的问题:我们不能将基类转换为派生类(请参阅Convert base class to derived class)这是完全合乎逻辑的,我理解为什么必须这样。但是我实际上不需要一个“整个”类,我只需要一个名称不同的属性,具体取决于接收到的消息,它解析来自基类的数据。但我也不想要一个每个属性都写成public byte Message02_Value1 => Data[0] 的类。我想使用这个语法:MessageBaseClass.Message01.Value

我也可以在从流中获取数据的同时编写代码

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

但这感觉像是双重工作..

所以我的问题是:如何使用从基类解析数据的属性,具体取决于此类中的内容类型?

为了明确我想要什么,我写了这段代码(实际上不起作用)

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

【问题讨论】:

  • 所以你的目标是在你的代码中有大约 100 个派生类?也许是我,但听起来肯定有比这更好的方法..
  • 我认为您拥有的if (func... 没有任何问题,只需将其放入消息工厂,将您的流转换为消息实例,恕我直言。然后你可以为你的消息类使用继承或只是一个接口,它会有类似.showMeData() 的东西,你很好,这样你的工厂是唯一关心你实例化什么类的地方。
  • 为了维护,生成代码可能会更好。即使您/我们提出了一个很棒的设计,生成代码也会大大减少消息更改的影响

标签: c# oop


【解决方案1】:

您尝试采用的方法根本上是错误的,原因与打开类的运行时类型是错误的原因相同。本质上,您正在做同样的事情,将类型替换为其数字代码。

C# 为处理子类提供了一个很好的选择,无需显式分派类型:为单个类型创建重载,将消息强制转换为 dynamic,并让 C# 为您调用正确的重载:

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

【讨论】:

  • 还有比这更好的替代方案吗?
  • @EhsanSajjad 这是一个多分派问题。它有许多面向对象语言的解决方案,但没有一个是理想的。我已经用了好几年了,到目前为止它没有给我带来任何麻烦。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-06
  • 2017-09-30
  • 1970-01-01
  • 1970-01-01
  • 2020-05-31
相关资源
最近更新 更多