这是一个场景:
我使用的是第三方SDK dll,我应该向几乎所有的dll方法传递一个PREDEFINED
字符串参数,并且存在800多个预定义的可能字符串可以传递给该方法,文档非常差,示例已经过时,有问题的dll是MediaInfoLib
,字符串是区分大小写的,因此很容易发生错误(任何人都可以记住这800个字符串的语法…),所以我想把所有可能的值放在枚举中,以调用这样的方法:
sub method(byval param as myEnum)
call API method(param.tostring)
End sub
这样,任何错误都可能发生,因为正确的字符串库语法是我在枚举中指定的,而且还有一个优点,那就是我不需要记住800个字符串的语法,我可以从枚举中选择所需的值。
问题是有些字符串是这样命名的:
StreamKind/String
CodecID/Url
我无法将/char放在枚举中。
当然,我想过用"_"字符替换"/"字符,但我不能这样做,因为存在其他一些字符串名称:
CodecID_Description
Width_Offset
所以如果我替换这些字符,我会得到一个假阳性。
那我该怎么办?
我找不到任何可以在枚举中使用的特殊字符,因为它与VB运算符冲突。。。
我想知道是否存在枚举的接受/禁止字符列表,或者是否有人知道我可以使用的一个好的特殊字符,而不是"/"字符?,对于特殊字符,我指的是任何人,但不是像这样的字母表:ññÇç,因为我正在搜索一个看起来像分隔符的可接受字符。
或者其他想法?
我使用MediaInfo.DLL(很多),知道你在说什么。首先,您可以捕获所有参数以及它们通过其中一个Info方法返回的内容,并将其保存到文本文件中,例如:
Info_Parameters (this is the mediaInfo key to use to tell it
to dump all the params it knows)
General
Count : Number of objects available in this stream
Status : bit field (0=IsAccepted, 1=IsFilled, 2=IsUpdated, 3=IsFinished)
StreamCount : Number of streams of this kind available
StreamKind : Stream type name
显而易见的答案是,您正试图将Enum几乎用作类:这不仅仅是代码中的一个有意义的标识符,您还希望在其他地方将名称用作参数。去过那里,做了那件事。我是这样处理的(这不会完全回答你的问题,因为你已经有了答案):
Friend Enum MediaInfoItem As Integer
<Description("File name"), MIKey("FileName"), MIGrp(MediaInfoGroup.File), MIDtl(True)> FileName
<Description("File Size"), MIKey("FileSize"), MIGrp(MediaInfoGroup.File), MIDtl(True), MIFmt(True)> FileSize
<Description("Duration"), MIKey("Duration"), MIGrp(MediaInfoGroup.File), MIDtl(True), MIFmt(True)> Duration
<Description("Format Profile"), MIKey("Format_Profile"), MIGrp(MediaInfoGroup.File), MILvl(PropLvl.XTD)> FormatProfile
' mp3 type stuff are in the general, not audio stream
<Description("Album"), MIKey("Album"), MIGrp(MediaInfoGroup.File), MILvl(PropLvl.DLG)> Album
<Description("Artist"), MIKey("Artist"), MIGrp(MediaInfoGroup.File), MILvl(PropLvl.DLG)> Artist
'...
<Description("Audio Format"), MIKey("Format"), MIGrp(MediaInfoGroup.Audio), MIDtl(True)> AudioFormat
<Description("Format Info"), MIKey("Format/Info"), MIGrp(MediaInfoGroup.Audio)> AudioFormatInfo
<Description("Format Profile"), MIKey("Format_Profile"), MIGrp(MediaInfoGroup.Audio), MILvl(PropLvl.XTD)> AudioFormatProfile
<Description("Codec"), MIKey("Codec/String"), MIGrp(MediaInfoGroup.Audio), MIDtl(True)> AudioCodec
<Description("Video Format"), MIKey("Format"), MIGrp(MediaInfoGroup.Video), MIDtl(True)> VideoFormat
<Description("Video Format Info"), MIKey("Format/Info"), MIGrp(MediaInfoGroup.Video)> VideoFormatInfo
<Description("Format Profile"), MIKey("Format_Profile"), MIGrp(MediaInfoGroup.Video), MILvl(PropLvl.XTD)> VideoFormatProfile
<Description("Codec"), MIKey("Codec/String"), MIGrp(MediaInfoGroup.Video)> VideoCodec
...
我在这里面用了50多个。您可能没有,但我有一个问题,那就是许多参数都是相同的:编解码器对于音频和视频是相同的("编解码器/字符串"),并且是流参数的变化使"编解码器"对于枚举名称无效。因为有这么多参数是相同的,Enum提供了一种很好的方法,可以将它们粘贴到正确的参数上,并将其与一个唯一的标识符相关联。
我使用自定义属性来分离、分类和跟踪每个条目的参数:
- Description是要在output/UI中使用的文本(我认为这与其中一个注释链接的DisplayName属性没有太大区别,至少就获取而言,但我会研究一下。)
- MIKey是用于获取此信息的MediaInfo.DLL密钥
- MIGrop告诉在MediaInfo中轮询哪个流(文件、音频、视频),并控制在ListView中显示时使用哪个组(我还有一个"虚拟"组,我不会进入)
- MIDtl和MILvl是使用此功能的应用程序的指示器
- MIFmt确定MediaInfo的返回是否需要格式化才能有用
如果您定义的属性包含一个默认的返回值,您可以跳过值为默认值的装饰(例如,我的MILvl默认为"Standard"),然后您可以在循环中创建一个列表(MediaInfoItem):
Private Sub BuildPropList()
Dim vals As MediaInfoItem() = [Enum].GetValues(GetType(MediaInfoItem))
Dim mi As MIProp
For Each n As MediaInfoItem In vals
mi = New MIProp(n) ' magic happens here
_props.Add(mi)
Next
End Sub
轮询MediaInfo以获取信息只需浏览propsList并将存储的参数提供给MediaInfo即可:要轮询的流是MIGrp,属性密钥来自MIKey,这可能就是您所需要的(我的实现还存储输出、格式化输出等)。要在开发过程中添加新项,只需添加一个新的Enum项即可。(我使用List(of T),以便保留顺序,并避免DisplayOrder属性(请参阅下面的链接),您可能希望Dictionary通过Enum值获取各种MediaInfo属性。)
我有3个应用程序使用这个,其中一个是Explorer外壳扩展。除了MediaInfoitem List之外,不需要任何代码,只需要将数据发布到ListView中进行显示(MIGrp的另一个用途,只是另一个循环)。
HTH
鉴于您的方法,您可能需要考虑以下内容(这不适合发表评论)。您的Enum Maker对params进行排序,听起来您计划使用Enum名称作为对MediaInfo的param请求(文章中的第1项)。如果添加伪造的MaxGeneral、MaxAudio和MaxVideo条目,您可以很容易地确定要使用哪个streamKind参数。
MediaInfoParms
Filename
fileSize
'...
EPG_Positions_End ' i think this is the last General one
MAX_GENERAL = EPG_Positions_End
' long list of Video enums
BufferSize ' last Video I think
MAX_VIDEO = BufferSize
....
现在,当你去呼叫MediaInfo:
Select Case thisEnumVal
Case Is =< MediaInfoParms.MAX_GENERAL
streamKind = MediaInfo.streamGeneral
Case Is =< MediaInfoParms.MAX_AUDIO
streamKind = MediaInfo.streamAudio
'...
Info_Parameters
已经将它们分组,您的EnumMaker只需要查找"常规"、"音频"one_answers"视频"作为一行中的唯一文本,就可以知道每个组的起始位置(您的EnamMaker目前也将这些标题作为枚举值包含在内)。
或者,您的EnumMaker可以只跟踪每个组的末尾,并在End Enum
:之后添加常量定义
Public Const Max_MediaInfo_General = 278 '(whatever value)
Public Const Max_MediaInfo_Video = 482
如果枚举是一个"库",而你实际上使用了应用程序中实际需要的子集(其中许多只是因为它在某个模糊的标准中被定义为合法标记而存在),那么让EnumMaker添加值(BufferSize = 482
)并使用Const定义,以便它们在子集中保持同步。
HTH
我想分享我的解决方案,这段代码以CSV列表的形式检索MediaInfo参数,并过滤该列表以编写Enum成员及其摘要文档。
需要澄清的一些事项:
-
参数表是连接和排序的,因此它们与mediainfo.dll
GetInfoI
方法(需要Integer)不匹配,顺便说一句,这个Enum可以与需要String的GetInfo
方法完美地使用,目的是避免使用GetInfoI
,因为有了这个Enum,我认为GetInfoI
方法已经过时,没有使用完。 -
生成的Enum大约有3.000行,它需要手动删除一些重复项,大约20个重复项,只需要5分钟即可删除。
-
/
字符被__
替换,所以我重写了原始的MediaInfo VBNET SDK示例,这就是我的方法的样子:''' <summary> ''' Gets a piece of information about a file. ''' </summary> ''' <param name="StreamKind"> ''' Kind of stream (general, video, audio...). ''' </param> ''' <param name="StreamNumber"> ''' Stream number in this kind of stream (first, second...). ''' </param> ''' <param name="Info"> ''' The information to retrieve. ''' </param> ''' <param name="KindOfInfo"> ''' Kind of information you want about the parameter (the text, the measure, the help...). ''' </param> ''' <param name="KindOfSearch"> ''' Where to look for the parameter . ''' </param> Public Function GetInfo(ByVal StreamKind As StreamKind, ByVal StreamNumber As Integer, ByVal Info As MediaInfoOption, Optional ByVal KindOfInfo As InfoKind = InfoKind.Text, Optional ByVal KindOfSearch As InfoKind = InfoKind.Name) As String Return System.Runtime.InteropServices. Marshal.PtrToStringUni(SafeNativeMethods. MediaInfo_Get(Handle, New IntPtr(StreamKind), New IntPtr(StreamNumber), Info.ToString.Replace("_s_", "(s)").Replace("__", "/"), New IntPtr(KindOfInfo), New IntPtr(KindOfSearch))) End Function
以下是生成Enum:的代码
Private Sub MakeMediaInfoEnum() Handles MyBase.Shown
Dim TempFile As String = IO.Path.GetTempFileName
Dim OutFile As String = "C:MediaInfo Enum.vb"
Dim ReplaceChar1 As String = "__" ' Replacement for "/" char.
Dim ReplaceChar2 As String = "_s_" ' Replacement for "(s)" chars.
Dim sb As New System.Text.StringBuilder
IO.File.WriteAllText(TempFile,
New MediaInfo().LibraryInfo(MediaInfo.MediaInfoLibInfo.Info_Parameters_CSV),
System.Text.Encoding.Default)
sb.AppendLine("Public Enum MediaInfoOption")
sb.AppendLine("")
For Each line As String In IO.File.ReadLines(TempFile,
System.Text.Encoding.Default).
Where(Function(l) _
l.Contains(";") _
AndAlso Not l.ToLower.Contains("deprecated") _
AndAlso Not l.ToLower.StartsWith("default") _
AndAlso Not l.ToLower.StartsWith("forced") _
AndAlso Not l.ToLower.StartsWith("bits-(iixel*frame)")).
OrderBy(Function(l) l).
Distinct()
sb.AppendLine("''' <summary>")
sb.AppendLine("''' " & If(Not String.IsNullOrEmpty(line.Substring(line.IndexOf(";") + 1)),
line.Substring(line.IndexOf(";") + 1),
"( UNDOCUMENTED PARAMETER )"))
sb.AppendLine("''' </summary>")
sb.AppendLine(line.Substring(0, line.IndexOf(";")).
Replace("/", ReplaceChar1).
Replace("(s)", ReplaceChar2))
sb.AppendLine("")
Next
sb.AppendLine("End Enum")
IO.File.WriteAllText(OutFile, sb.ToString, System.Text.Encoding.Default)
End Sub
上面的代码生成一个文本文件,如下所示:
Public Enum MediaInfoOption
''' <summary>
''' Format used
''' </summary>
Format
''' <summary>
''' Commercial name used by vendor for theses setings or Format field if there is no difference
''' </summary>
Format_Commercial
''' <summary>
''' Commercial name used by vendor for theses setings if there is one
''' </summary>
Format_Commercial_IfAny
''' <summary>
''' Compression method used
''' </summary>
Format_Compression
''' <summary>
''' Profile of this Format
''' </summary>
Format_Profile
''' <summary>
''' Settings needed for decoder used
''' </summary>
Format_Settings
etc...
End Enum
这是我从SDK中获得的原始MediaInfo
vbnet类的完整重写版本(我希望我以正确的方式修改了代码,但我不是大师)。
我添加了文档、方法重载、枚举,并且(对我来说)从原始代码中删除了一些不有用的东西,比如未实现的方法以及StreamKind
枚举的menu
和chapters
成员。
http://pastebin.com/XGUwW8hQ