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

Media Transport Protocolを表す proto フラグを見てください。仕様によると、このフィールドには次の値を指定できます。

  • RTP/AVP
  • RTP/SAVP
  • UDP

これは値のリストなので、列挙するのが適切であることは明らかです。

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

おっと!しかし、これは「/」文字のために機能しません。では、これを解析に使用するにはどうすればよいでしょうか。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 . この回答は、IMHOの醜いソリューションであっても、それらを切り替え可能にするソリューションについても説明しています。

ただし、これは定義された範囲でのみ機能します。解析中に検索できるインスタンスを格納するために辞書を使用してクラスを拡張しましたType Safe Enumerationが、インスタンスがない場合は新しいインスタンスも追加しました。

しかし、他のすべての分野はどうですか?そして、キャスティングはどうですか?

この回答は、基本クラスを使用したアプローチと、明示的な演算子によるキャストについて説明しています: Casting string to type-safe-enum using user-defined conversion

やってみたのですが、思ったようにうまくいきません。(無効なキャスト例外、汚い 2 つのキャスト パターン、拡張不可)。

正しい 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)
{
}

また、parse は、"RTP/" (仕様で定義されている) で始まる限り、未知の/将来のプロトコル タイプを返します。

もちろん問題は、ライブラリが「未知の」プロトコルを処理できるかどうかです。できない場合は、それらの解析を許可しないでください。NotSupportedException新しいプロトコルが追加されたら、ライブラリをスローして更新する必要があります。または、他の人に拡張してもらいたい場合は、特定のプロトコルを処理する実装を他の人が定義できるようにする必要があります。

于 2013-07-18T09:22:35.867 に答える