在设计程序时,无论是界面或是后台代码,我们通常都想留给用户一个较为简单的接口。而我在参与封装语音卡开发函数包的时候,发现各种语音卡的底层函数的接口都是各种整形变量标记值,使用起来极为不变。于是就理解了前辈所写的代码中,利用XML构建反射表机制的初衷。下面我就以某一种语音卡所能兼容的语音格式为例,将反射表机制的原理做个示范。
语音卡的底层开发函数中,放音和录音函数的参数都是很多而且不易理解和记忆的。以语音格式为例,假如a率的标记值是6,u率的标记值是7,……,一般所能兼容的语音格式为10多个。如果我们选用整形变量来做标记语音格式的参数,那么我们大概就有两种选择:1.要么我们把这种对应关系生记下来,2.要么我们在调用函数时去查一下对照表,而这两种方式,都需要做不必要的投入。
这时反射表的优势就表现出来了,下面看看例子:
//先做一个语音格式的枚举,方便用户调用:
Code
enum 语音格式
![ExpandedBlockStart.gif](http://img.e-com-net.com/image/info8/a851f6ebab08498cbe1d2f2c2b23a0c9.gif)
{
未定义 = -1,
a率 = 0,
u率 = 1,
PCM16 = 2,
PCM8 = 3,
GSM = 4,
ADPCM = 5,
VOX = 6,
MP3 = 7,
G729 = 8,
G723 = 9,
GC8 = 10,
}
//这是一个语音格式类,用于填充语音格式对照表
Code
class PhoneticMatrix
![ExpandedBlockStart.gif](http://img.e-com-net.com/image/info8/a851f6ebab08498cbe1d2f2c2b23a0c9.gif)
{
XmlNodeList nodeList = null;
XmlNode node=null;
//填充语音格式对照表
public readonly Dictionary<语音格式, int> 语音格式对照表 = new Dictionary<语音格式, int>();
public void FillDirectory(string 配置文件名)
![ExpandedSubBlockStart.gif](http://img.e-com-net.com/image/info8/c258b09401044c33a0d619608a74e55d.gif)
{
XmlDocument xDoc = new XmlDocument();
xDoc.Load(配置文件名);
![](http://img.e-com-net.com/image/info8/631f42b035dc4497b25c141371b40678.gif)
//选择格式“结点”列表
nodeList = xDoc.SelectNodes("/语音格式/格式");
foreach(XmlNode nodes in nodeList)
![ExpandedSubBlockStart.gif](http://img.e-com-net.com/image/info8/c258b09401044c33a0d619608a74e55d.gif)
{
//选取结点“名称”,并读取结点值
node=nodes.SelectSingleNode("名称");
string s名称=node.FirstChild.Value;
![](http://img.e-com-net.com/image/info8/631f42b035dc4497b25c141371b40678.gif)
//选取结点“编号”,并读取结点值
node = nodes.SelectSingleNode("编号");
string s编号 = node.FirstChild.Value;
int i编号 = int.Parse(s编号);
![](http://img.e-com-net.com/image/info8/631f42b035dc4497b25c141371b40678.gif)
//填充语音格式对照表
语音格式 当前语音格式 = (语音格式)Enum.Parse(typeof(语音格式), s名称);
语音格式对照表.Add(当前语音格式, i编号);
}
}
//编写一个方法,用来演示语音格式对照表的使用,具体使用方法类似但要视情况而定
Code
//显示所选取的语音格式的配置编号
public int ShowFormatID(语音格式 用户选项)
![ExpandedBlockStart.gif](http://img.e-com-net.com/image/info8/a851f6ebab08498cbe1d2f2c2b23a0c9.gif)
{
int i语音格式编号;
![](http://img.e-com-net.com/image/info8/631f42b035dc4497b25c141371b40678.gif)
//查询选定的枚举项所对应的配置值
语音格式对照表.TryGetValue(用户选项, out i语音格式编号);
Console.WriteLine("用户选定项:"+用户选项.ToString()+";该选项所对应的配置值为:"+i语音格式编号.ToString());
return i语音格式编号;
}
//最后贴出测试用的Main函数
Code
class Program
![ExpandedBlockStart.gif](http://img.e-com-net.com/image/info8/a851f6ebab08498cbe1d2f2c2b23a0c9.gif)
{
static void Main(string[] args)
![ExpandedSubBlockStart.gif](http://img.e-com-net.com/image/info8/c258b09401044c33a0d619608a74e55d.gif)
{
//获取当前工作目录
string dir = Directory.GetCurrentDirectory();
//生成文件路径
string actualDir = dir + "\\语音格式.xml";
![](http://img.e-com-net.com/image/info8/631f42b035dc4497b25c141371b40678.gif)
PhoneticMatrix pm = new PhoneticMatrix();
pm.FillDirectory(actualDir);
![](http://img.e-com-net.com/image/info8/631f42b035dc4497b25c141371b40678.gif)
int i格式编号 = pm.ShowFormatID(语音格式.a率);
Console.ReadLine();
}
}
//最后给出测试用的XML文件:
Code
xml version="1.0" encoding="utf-8" ?>
<语音格式>
<格式>
<名称>a率名称>
<编号>6编号>
格式>
<格式>
<名称>u率名称>
<编号>7编号>
格式>
<格式>
<名称>GSM名称>
<编号>49编号>
格式>
<格式>
<名称>ADPCM名称>
<编号>17编号>
格式>
<格式>
<名称>VOX名称>
<编号>23编号>
格式>
<格式>
<名称>MP3名称>
<编号>85编号>
格式>
<格式>
<名称>G729名称>
<编号>65411编号>
格式>
<格式>
<名称>G723名称>
<编号>0编号>
格式>
<格式>
<名称>PCM16名称>
<编号>-2编号>
格式>
<格式>
<名称>PCM8名称>
<编号>1编号>
格式>
<格式>
<名称>GC8名称>
<编号>131编号>
格式>
<格式>
<名称>未定义名称>
<编号>-1编号>
格式>
语音格式>
//输出结果:
用户选定项:a率;该选项的配置值为:6
这种处理方法,可以在许多方面得到应用。例如在语音卡的事件处理过程中,诸如外拨事件、放音事件及录音事件等操作,在这种过程性的事件响应中,都需要利用反射机制将通道状态来输出。