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

时间:2013-07-18 08:52:41

标签: c# .net parsing protocols

我现在已经完全坚持了大约两天,似乎我无法理解我面临的问题。

目前,我正在编写一个SDP解析库,该库也应该可用于根据其规范(http://tools.ietf.org/html/rfc4566)创建正确的SDP消息。但规范有时非常开放或不清楚,所以我尝试实现必要的灵活性,同时尽可能接近RFC。

示例问题

SDP消息可以包含媒体信息(" m"字段),因为此信息具有以下模式:

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

示例消息可能如下所示:

m=video 49170/2 RTP/AVP 31

查看proto标志,代表媒体传输协议。根据规范,该字段可以具有以下值:

  • RTP / AVP
  • RTP / SAVP
  • UDP

这是一个值列表,因此显然适合采用枚举。

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

哎呀!但这并不是因为&#34; /&#34;焦炭。那么,我怎么能用它来解析呢?我使用Enumeration

扩展了DescriptionAttribute字段
public enum MediaTransportProtocolType {
    [Description("RTP/AVP")
    RTP_AVP
    [Description("RTP/SAVP")
    RTP_SAVP
    [Description("UDP")
    UDP
}

现在我可以通过它的描述简单地查找适当的媒体传输协议类型。但现在,RFC规范仍在继续:

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

未来的网络设备可能会向我发送一个我不知道的媒体传输协议。由于各种原因System.Enum不可扩展,因此整个枚举事情不再起作用。

解决方案

在寻找解决方案的过程中,我遇到了类型安全枚举模式(AKA StringEnum),如下所述:how can i use switch statement on type-safe enum pattern。这个答案甚至描述了一个让它们可以切换的解决方案,即使它是一个丑陋的解决方案恕我直言。

但同样,这只适用于定义的范围。我使用字典扩展了Type Safe Enumeration类来存储我可以在解析时查找的实例,但如果我现在不添加新实例,那么我也会添加新的实例。

但是所有其他领域呢?那么铸造呢?

这里的答案描述了一种使用基类并通过显式运算符进行转换的方法:Casting string to type-safe-enum using user-defined conversion

我试了一下,但它并没有像我希望的那样工作。 (无效的强制转换异常,脏的两个强制转换模式,不可扩展)。

如何在提供允许创建正确SDP的库的同时正确轻松地解析SDP信息?

1 个答案:

答案 0 :(得分:1)

您可以这样做:

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

这允许你将它用作这样的枚举:

var type = MediaTransportProtocolType.Udp;

你可以解析它:

var type = MediaTransportProtocolType.Parse(value);

迭代所有已知值:

foreach (var type in MediaTransportProtocolType.Values)
{
}

并且解析返回未知/未来协议类型,只要它们以“RTP /”开头(由规范定义)。

当然问题是,您的图书馆可以处理“未知”协议。如果你不能,你不应该允许解析它们。您应该抛出NotSupportedException并在添加新协议时更新库。或者,如果您希望其他人扩展,您应该允许其他人定义处理特定协议的实现。