C# 用于解析的可扩展类型安全枚举类?
我现在完全被这个问题困扰了大约两天,似乎我根本无法解决我所面临的问题 目前,我正在编写一个SDP解析库,该库还可以用于根据规范()创建正确的C# 用于解析的可扩展类型安全枚举类?,c#,.net,parsing,protocols,C#,.net,Parsing,Protocols,我现在完全被这个问题困扰了大约两天,似乎我根本无法解决我所面临的问题 目前,我正在编写一个SDP解析库,该库还可以用于根据规范()创建正确的SDP消息。但规范有时非常开放或不明确,因此我尝试实现必要的灵活性,同时尽可能接近RFC 示例问题 SDP消息可以包含媒体信息(“m”字段),其中该信息具有以下模式: m=<media> <port> <proto> <fmt> ... 看看proto标志,它代表媒体传输协议。根据规范,此字段可以具有以下值:
SDP
消息。但规范有时非常开放或不明确,因此我尝试实现必要的灵活性,同时尽可能接近RFC
示例问题
SDP消息可以包含媒体信息(“m
”字段),其中该信息具有以下模式:
m=<media> <port> <proto> <fmt> ...
看看proto标志,它代表媒体传输协议。根据规范,此字段可以具有以下值:
- RTP/AVP
- RTP/SAVP
- UDP
public enum MediaTransportProtocolType {
RTP/AVP
RTP/SAVP
UDP
}
哎呀!但由于“/”字符的存在,这不起作用。那么,我如何能够使用它进行解析呢?我使用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 [...]
因此,未来的网络设备可能会向我发送我不知道的媒体传输协议。作为系统,整个枚举在这里不再起作用。由于各种原因,Enum
不可扩展
解决方案
在寻找解决方案的过程中,我遇到了类型安全枚举模式(又称StringEnum
),如下所述:。这个答案甚至描述了一个使它们可切换的解决方案,即使这是一个丑陋的解决方案
但同样,这只适用于定义的范围。我用一个字典扩展了类型安全枚举
类,以存储我可以在解析时查找的实例,但如果现在没有实例,还可以添加新实例
但是其他领域呢?那铸造呢
这里的答案描述了一种使用基类并通过显式运算符强制转换的方法:
我试过了,但不是我想要的那样。(无效的强制转换异常,脏的两次强制转换模式,不可扩展)
如何在提供允许创建正确SDP的库的同时正确、轻松地解析SDP信息?您可以执行以下操作:
m=video 49170/2 RTP/AVP 31
公共密封类MediaTransportProtocolType
{
公共静态只读MediaTransportProtocolType RtpAvp=
新的MediaTransportProtocolType(“RTP/AVP”);
公共静态只读MediaTransportProtocolType RtpSavp=
新的MediaTransportProtocolType(“RTP/SAVP”);
公共静态只读MediaTransportProtocolType Udp=
新的MediaTransportProtocolType(“UDP”);
公共静态只读只读只读集合
值=新的只读集合(
新的MediaTransportProtocolType[]{RtpAvp、RtpSavp、Udp});
私有MediaTransportProtocolType(字符串名称)
{
this.Name=Name;
}
公共字符串名称{get;private set;}
公共静态MediaTransportProtocolType解析(字符串值)
{
if(string.IsNullOrEmpty(value))
{
抛出新的ArgumentNullException(“值”);
}
var comparer=StringComparer.OrdinalIgnoreCase;
if(comparer.Equals(value,RtpAvp.Name))
{
返回RtpAvp;
}
else if(comparer.Equals(value,RtpSavp.Name))
{
返回RtpSavp;
}
else if(comparer.Equals(value,Udp.Name))
{
返回Udp;
}
else if(value.StartsWith(“RTP/”,StringComparison.OrdinalIgnoreCase))
{
//通常我们会在这里抛出一个异常,但将来
//协议是预期的,我们必须是向前兼容的。
返回新的MediaTransportProtocolType(名称);
}
抛出新的格式化异常(
该值的格式不符合要求。值:“+value”);
}
}
允许您将其用作如下枚举:
m=video 49170/2 RTP/AVP 31
var type=MediaTransportProtocolType.Udp;
您可以解析它:
var type=MediaTransportProtocolType.Parse(值);
并迭代所有已知值:
foreach(MediaTransportProtocolType.Values中的变量类型)
{
}
和parse返回一个未知/未来的协议类型,只要它们以“RTP/(由规范定义)开头
当然,问题是,您的库能否处理“未知”协议。如果不能,就不应该允许解析它们。您应该抛出一个
NotSupportedException
,并在添加新协议时更新库。或者,如果您希望其他人进行扩展,您应该允许其他人定义处理特定协议的实现。如果我了解您的要求,您的库必须具有“可扩展行为”,这意味着:如果将来添加更多协议类型,如果找到其中一些协议类型,则必须发生不同的行为。因此,我会考虑一个可插拔的体系结构:尝试定义需要可扩展性的接口;然后,为接口的每个实现创建不同的程序集;在运行时,您将加载所有程序集,并通过配置文件将接口映射到实现所需行为的类。查看unity.codeplex。com@br1那完全是白费力气。其思想不是扩展行为,而是允许枚举中有新值。插件体系结构在这里太过分了。只有@Atrotygma可以确认这一点,但我想在他的代码中的某个地方,他将根据枚举变量的值“切换”他的库的行为。@br已确认。一个简单解析器的插件架构就像一只狗在挖一个10英尺的洞来隐藏他的骨头:他说