2

我现在完全坚持了大约 2 天,似乎我根本无法解决我面临的问题。

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

示例问题

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

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

示例消息可能如下所示:

m=video 49170/2 RTP/AVP 31

看一下 proto 标志,它代表Media Transport Protocol。根据规范,该字段可以具有以下值:

  • RTP/AVP
  • RTP/SAVP
  • UDP

这是一个值的列表,因此进行枚举显然是合适的。

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

哎呀!但这不起作用,因为“/”字符。那么,我怎样才能使用它进行解析呢?我EnumerationDescriptionAttribute

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),如下所述:我如何在类型安全枚举模式上使用 switch 语句。这个答案甚至描述了一种使它们可切换的解决方案,即使它是一个丑陋的解决方案恕我直言。

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

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

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

我试过了,但它并没有按照我想要的方式工作。(无效的转换异常,脏的两次转换模式,不可扩展)。

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

4

1 回答 1

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/”(由规范定义)开头,parse 就会返回一个未知/未来的协议类型。

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

于 2013-07-18T09:22:35.867 回答