简体   繁体   English

用于分析的可扩展类型安全枚举类?

[英]Extendable type-safe enumeration classes for parsing?

I'm completely stuck with this for about 2 days now and it seems I simply can't get my head around the problem I'm facing. 我已经完全坚持了大约2天,看来我无法直面所面临的问题。

Currently, I'm writing an SDP parsing library that should also be usable for creating correct SDP messages according to it's specification ( http://tools.ietf.org/html/rfc4566 ). 当前,我正在编写一个SDP解析库,该库也可用于根据其规范( http://tools.ietf.org/html/rfc4566 )创建正确的SDP消息。 But the specification is sometimes very open or unclear, so I try to implement a necessary amount of flexibility while still being as close to the RFC as possible. 但是规范有时是非常开放或不清楚的,因此我尝试实现必要的灵活性,同时仍尽可能接近RFC。

Example Problem 示例问题

A SDP message can contain media information (" m " field) where as this information has the following pattern: SDP消息可以包含媒体信息(“ m ”字段),其中该信息具有以下模式:

m=<media> <port> <proto> <fmt> ...

And example message could look like this: 消息示例如下所示:

m=video 49170/2 RTP/AVP 31

Take a look at the proto flag, which stands for Media Transport Protocol . 看一下proto标志,它代表Media Transport Protocol According to the specification, this field can have the following values: 根据规范,该字段可以具有以下值:

  • RTP/AVP RTP / AVP
  • RTP/SAVP RTP / SAVP
  • UDP UDP

This is a list of values, so it's obviously appropriate to take an enumeration. 这是一个值列表,因此显然应该进行枚举。

public enum MediaTransportProtocolType {
    RTP/AVP
    RTP/SAVP
    UDP
}

Ooops! 哎呀! But this doesn't work because of the "/" char. 但这由于“ /”字符而无效。 So, how am I able to use this for parsing? 那么,我如何使用它进行解析? I extended the Enumeration fields with the DescriptionAttribute 我用DescriptionAttribute扩展了Enumeration字段

public enum MediaTransportProtocolType {
    [Description("RTP/AVP")
    RTP_AVP
    [Description("RTP/SAVP")
    RTP_SAVP
    [Description("UDP")
    UDP
}

Now I can simply look up the appropriate media transport protocol type by it's description. 现在,我可以通过其描述简单地查找适当的媒体传输协议类型。 But now, the RFC specification goes on: 但是现在,RFC规范继续进行:

This memo registers three values [...] If other RTP profiles are 
defined in the future [...]

So it's possible that a future network device can send me an media transport protocol that I'm not aware of. 因此,将来的网络设备可能会向我发送我不知道的媒体传输协议。 The whole enumeration thing doesn't work here anymore as System.Enum is not extendable due to various reason. 整个枚举在这里不再起作用,因为System.Enum由于各种原因而无法扩展。

Solution

On my way looking for a solution I met the Type Safe Enumeration Pattern (AKA StringEnum ) as described in here: how can i use switch statement on type-safe enum pattern . 在寻找解决方案的过程中,我遇到了类型安全枚举模式 (AKA StringEnum ),如此处所述: 如何在类型安全的枚举模式上使用switch语句 This answer even describes a solution to make them switchable, even if it's an ugly solution IMHO. 这个答案甚至描述了使它们可切换的解决方案,即使它是丑陋的解决方案恕我直言。

But again, this does only work for a defined range. 但是同样,这仅适用于定义的范围。 I extended the Type Safe Enumeration class with a dictionary to store instances that I can look up while parsing, but also add new ones if I don't now them. 我用字典扩展了Type Safe Enumeration类,以存储可以在解析时查找的实例,如果现在不添加它们,还可以添加新实例。

But what about all the other fields? 但是其他所有领域呢? And what about casting? 那铸造呢?

This answer here describes an approach with a base class and casting through explicit operators: Casting string to type-safe-enum using user-defined conversion 这里的答案描述了一种使用基类并通过显式运算符进行强制转换的方法: 使用用户定义的转换将字符串强制转换为类型安全枚举

I tried it out, but it's not working the way I'd like it to be. 我尝试了一下,但是没有按照我想要的方式工作。 (Invalid casting exceptions, dirty two casts pattern, not extendable). (无效的强制转换异常,脏的两个强制转换模式,不可扩展)。

How does one parse SDP information correctly and easily while still providing a library that allows to create a correct SDP? 如何在仍提供允许创建正确SDP的库的同时正确而轻松地解析SDP信息?

You can do something like this: 您可以执行以下操作:

public sealed class MediaTransportProtocolType
{
    public static readonly MediaTransportProtocolType RtpAvp =
        new MediaTransportProtocolType("RTP/AVP");

    public static readonly MediaTransportProtocolType RtpSavp =
        new MediaTransportProtocolType("RTP/SAVP");

        public static readonly MediaTransportProtocolType Udp =
        new MediaTransportProtocolType("UDP");

    public static readonly ReadOnlyCollection<MediaTransportProtocolType>
        Values = new ReadOnlyCollection<MediaTransportProtocolType>(
            new MediaTransportProtocolType[] { RtpAvp, RtpSavp, Udp });

    private MediaTransportProtocolType(string name)
    {
        this.Name = name;
    }

    public string Name { get; private set; }

    public static MediaTransportProtocolType Parse(string value)
    {
        if (string.IsNullOrEmpty(value))
        {
            throw new ArgumentNullException("value");
        }

        var comparer = StringComparer.OrdinalIgnoreCase;

        if (comparer.Equals(value, RtpAvp.Name))
        {
            return RtpAvp;
        }
        else if (comparer.Equals(value, RtpSavp.Name))
        {
            return RtpSavp;
        }
        else if (comparer.Equals(value, Udp.Name))
        {
            return Udp;
        }
        else if (value.StartsWith("RTP/", StringComparison.OrdinalIgnoreCase))
        {
            // Normally we would throw an exception here, but  future
            // protocols are expected and we must be forward compatible.
            return new MediaTransportProtocolType(name);
        }

        throw new FormatException(
            "The value is not in an expected format. Value: " + value);
    }
}

That allows you to use it as an enum like this: 这样就可以将其用作如下枚举:

var type = MediaTransportProtocolType.Udp;

And you can parse it: 您可以解析它:

var type = MediaTransportProtocolType.Parse(value);

And iterate over all known values: 并遍历所有已知值:

foreach (var type in MediaTransportProtocolType.Values)
{
}

And parse returns a unknown/future protocol type as long as they start with "RTP/" (as defined by the specs). 只要parse以“ RTP /”(由规范定义)开头,parse就会返回未知/将来的协议类型。

Of course the question is, can your library handle 'unknown' protocols. 当然,问题是,您的库可以处理“未知”协议吗? If you can't, you shouldn't allow parsing them. 如果不能,则不允许解析它们。 You should throw an NotSupportedException and update the library when new protocols are added. 添加新协议后,应引发NotSupportedException并更新库。 Or if you want others to extend, you should allow others to define implementations that handle a specific protocol. 或者,如果您希望其他人扩展,则应允许其他人定义处理特定协议的实现。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM