【C#编程辅助】可动态配置的函数参数调用实现
源起:
经常使用编写单元测试,经常更改函数参数的传值,通过ParamsBuild配合配置文件配置就可以做到函数参数值可配置。
方便缩写的命名空间导入
1
using System;
2
using System.Xml.Serialization;
3
using System.Text.RegularExpressions;
4
using System.Collections.Generic;
5
using System.Diagnostics;
6
using System.Reflection;
7
using System.Xml;
第一部分:参数构建器(主题设计)
using System;2
using System.Xml.Serialization;3
using System.Text.RegularExpressions;4
using System.Collections.Generic;5
using System.Diagnostics;6
using System.Reflection;7
using System.Xml;
代码ParamsBuild /// <summary>
/// 参数构建器
/// </summary>
[Serializable]
public class ParamsBuild
{
/// <summary>
/// 获取或设置方法参数配置集合
/// </summary>
/// <value>The param config.</value>
[XmlElement(ElementName = "Config")]
public MethodParams[] ParamConfig { get; set; }
/// <summary>
/// 获取指定类型名称的方法参数
/// </summary>
/// <param name="typeFullName">类型全称</param>
/// <param name="methodName">方法名称</param>
/// <returns></returns>
public MethodParams GetParamConfig(string typeFullName, string methodName)
{
MethodParams result = null;
foreach (MethodParams pm in ParamConfig)
{
if (pm.TypeFullName == typeFullName && pm.MethodName == methodName)
{
result = pm;
break;
}
}
return result;
}
/// <summary>
/// 获取当前调用方法的方法参数配置
/// </summary>
/// <returns></returns>
public MethodParams GetParamConfig()
{
MethodBase method = new System.Diagnostics.StackFrame(1).GetMethod();
return GetParamConfig(method.DeclaringType.FullName, method.Name);
}
/// <summary>
/// 获取同类型中其他方法名的参数配置
/// </summary>
/// <param name="methodName">方法名称</param>
/// <returns></returns>
public MethodParams GetParamConfig(string methodName)
{
MethodBase method = new System.Diagnostics.StackFrame(1).GetMethod();
return GetParamConfig(method.DeclaringType.FullName, methodName);
}
private static ParamsBuild _instance;
/// <summary>
/// 获取配置文件中的实例
/// </summary>
public static ParamsBuild ConfigInstance
{
get
{
if (_instance == null)
{
_instance = XmlSerializeSectionHandler.GetObject<ParamsBuild>("ParamsBuild");
}
return _instance;
}
}
}
/// 参数构建器
/// </summary>
[Serializable]
public class ParamsBuild
{
/// <summary>
/// 获取或设置方法参数配置集合
/// </summary>
/// <value>The param config.</value>
[XmlElement(ElementName = "Config")]
public MethodParams[] ParamConfig { get; set; }
/// <summary>
/// 获取指定类型名称的方法参数
/// </summary>
/// <param name="typeFullName">类型全称</param>
/// <param name="methodName">方法名称</param>
/// <returns></returns>
public MethodParams GetParamConfig(string typeFullName, string methodName)
{
MethodParams result = null;
foreach (MethodParams pm in ParamConfig)
{
if (pm.TypeFullName == typeFullName && pm.MethodName == methodName)
{
result = pm;
break;
}
}
return result;
}
/// <summary>
/// 获取当前调用方法的方法参数配置
/// </summary>
/// <returns></returns>
public MethodParams GetParamConfig()
{
MethodBase method = new System.Diagnostics.StackFrame(1).GetMethod();
return GetParamConfig(method.DeclaringType.FullName, method.Name);
}
/// <summary>
/// 获取同类型中其他方法名的参数配置
/// </summary>
/// <param name="methodName">方法名称</param>
/// <returns></returns>
public MethodParams GetParamConfig(string methodName)
{
MethodBase method = new System.Diagnostics.StackFrame(1).GetMethod();
return GetParamConfig(method.DeclaringType.FullName, methodName);
}
private static ParamsBuild _instance;
/// <summary>
/// 获取配置文件中的实例
/// </summary>
public static ParamsBuild ConfigInstance
{
get
{
if (_instance == null)
{
_instance = XmlSerializeSectionHandler.GetObject<ParamsBuild>("ParamsBuild");
}
return _instance;
}
}
}
第二部分:方法参数配置
MethodParams /// <summary>
/// 方法参数配置
/// </summary>
[Serializable]
public class MethodParams : ICloneable
{
/// <summary>
/// 类型全称
/// </summary>
[XmlAttribute(AttributeName = "type")]
public string TypeFullName { get; set; }
/// <summary>
/// 方法名
/// </summary>
[XmlAttribute(AttributeName = "method")]
public string MethodName { get; set; }
/// <summary>
/// 参数集合
/// </summary>
public Param[] Params { get; set; }
/// <summary>
/// 获取参数集合中特定名称的参数
/// </summary>
/// <param name="paramName">参数名称</param>
/// <returns></returns>
public Param GetParam(string paramName)
{
Param p = null;
if (Params != null && Params.Length > 0)
{
foreach (Param pi in Params)
{
if (pi.Name == paramName)
{
p = pi;
break;
}
}
}
return p;
}
/// <summary>
/// [穷举]获取所有方法最个可能参数的的情况(各个参数可能情况的乘积)
/// </summary>
/// <returns></returns>
public MethodParams[] GetAvailableMethodParams()
{
List<MethodParams> mparmList = new List<MethodParams>();
bool addDefaultMethodParams = false;
List<Param> baseParams = new List<Param>();
foreach (Param pm in Params)
{
foreach (Param rpm in Params)
{
if (rpm.Name == pm.Name)
{
#region 当前参数
int totalCount = rpm.GetUsableValueCount();
//Console.WriteLine(rpm.Name + " : " + totalCount);
if (totalCount == 1)
{
if (rpm.IsOptional) baseParams.Add(rpm);
if (!addDefaultMethodParams)
{
MethodParams defaultMethodParams = new MethodParams();
defaultMethodParams.TypeFullName = TypeFullName;
defaultMethodParams.MethodName = MethodName;
defaultMethodParams.Params = Params;
mparmList.Add(defaultMethodParams);
addDefaultMethodParams = true;
}
}
else
{
#region 穷举参数的所有可能值清况
List<Param> rpmAvailableList = new List<Param>();
foreach (Param rpmAvailable in Params)
{
if (rpmAvailable.Name != rpm.Name)
{
rpmAvailableList.Add(rpmAvailable);
}
}
rpmAvailableList.Add(null);
int t = mparmList.Count;
//Console.WriteLine("Available Count:" + t);
for (int i = 0; i < totalCount; i++)
{
Param parmAvailale = (Param)rpm.Clone();
parmAvailale.Value = rpm.GetUsableValue(i).ToString();
rpmAvailableList[rpmAvailableList.Count - 1] = parmAvailale;
//小于一个单位
if (t < 1)
{
#region 基数为1单位时,加法即乘法。
MethodParams mparmAvailale = new MethodParams();
mparmAvailale.TypeFullName = TypeFullName;
mparmAvailale.MethodName = MethodName;
mparmAvailale.Params = rpmAvailableList.ToArray();
//Console.WriteLine("< 1 Unit,ADD:---" + parmAvailale.Value);
mparmList.Add(mparmAvailale);
#endregion
}
else
{
for (int k = 0; k < t; k++)
{
#region 乘以基数运算
MethodParams mparmInList = mparmList[k];
//Console.WriteLine(k);
bool blnAddNewMethodParam = true;
#region 检查是否有重复的方法参数定义
foreach (Param parminList in mparmInList.Params)
{
if (parminList.Name == rpm.Name)
{
if (parminList.Value == parmAvailale.Value)
{
blnAddNewMethodParam = false;
//Console.WriteLine("Not ADD:" + parmAvailale.Value);
break;
}
}
}
#endregion
if (blnAddNewMethodParam == true)
{
Param[] upataParams = new Param[mparmInList.Params.Length];
#region DeepClone
for (int u = 0; u < upataParams.Length; u++)
{
Param pu = (Param)mparmInList.Params[u].Clone();
upataParams[u] = pu;
}
#endregion
#region Update
int idx = 0;
foreach (Param parminListUpdate in mparmInList.Params)
{
if (parminListUpdate.Name == rpm.Name)
{
upataParams[idx].Value = parmAvailale.Value;
break;
}
idx++;
}
#endregion
MethodParams mparmNew = new MethodParams();
mparmNew.TypeFullName = TypeFullName;
mparmNew.MethodName = MethodName;
mparmNew.Params = upataParams;
//Console.WriteLine("Update:---" + parmAvailale.Value);
mparmList.Add(mparmNew);
}
#endregion
}
//Console.WriteLine("-----" + t + "*" + (i+1).ToString());
}
}
#endregion
}
if (rpm.IsOptional)
{
#region 该参数可选情况
if (mparmList.Count < 1)
{
List<Param> rpmOptionList = new List<Param>();
foreach (Param rpmOpt in Params)
{
if (rpmOpt.Name != rpm.Name)
{
rpmOptionList.Add(rpmOpt);
}
}
MethodParams mparmOpt = new MethodParams();
mparmOpt.TypeFullName = TypeFullName;
mparmOpt.MethodName = MethodName;
mparmOpt.Params = rpmOptionList.ToArray();
mparmList.Add(mparmOpt);
}
else
{
#region X2 可选操作
for (int ei = 0; ei < mparmList.Count; ei++)
{
List<Param> eiOptionList = new List<Param>();
foreach (Param rpmOpt in mparmList[ei].Params)
{
if (rpmOpt.Name != rpm.Name) eiOptionList.Add(rpmOpt);
}
Param[] eiToAddArray = eiOptionList.ToArray();
if (!ExistsMethodParams(mparmList, eiToAddArray))
{
MethodParams eiParmOpt = (MethodParams)mparmList[ei].Clone();
eiParmOpt.Params = eiToAddArray;
mparmList.Add(eiParmOpt);
}
}
#endregion
}
#endregion
}
#endregion
}
}
}
if (baseParams.Count == Params.Length)
{
MethodParams baseMethodParams = new MethodParams();
baseMethodParams.TypeFullName = TypeFullName;
baseMethodParams.MethodName = MethodName;
baseMethodParams.Params = baseParams.ToArray();
mparmList.Add(baseMethodParams);
}
return mparmList.ToArray();
}
/// <summary>
/// 检查所有的参数集合中是否存在指定的方法参数
/// </summary>
private bool ExistsMethodParams(List<MethodParams> plist, Param[] MethodParamsArray)
{
bool exists = false;
for (int ichk = 0; ichk < plist.Count; ichk++)
{
Param[] toCHKArray = plist[ichk].Params;
//参数个数不匹配
if (toCHKArray.Length != MethodParamsArray.Length)
{
continue;
}
else
{
int eqTotal = 0;
foreach (Param chkParam in toCHKArray)
{
for (int eic = 0; eic < MethodParamsArray.Length; eic++)
{
if (chkParam.Name == MethodParamsArray[eic].Name
&& chkParam.Value == MethodParamsArray[eic].Value)
{
eqTotal++;
}
}
}
if (eqTotal == MethodParamsArray.Length)
{
exists = true;
break;
}
}
}
return exists;
}
#region ICloneable 成员
/// <summary>
/// 创建作为当前实例副本的新对象。
/// </summary>
/// <returns>作为此实例副本的新对象。</returns>
public object Clone()
{
MethodParams m = new MethodParams();
m.TypeFullName = TypeFullName;
m.MethodName = MethodName;
Param[] mParams = new Param[Params.Length];
for (int i = 0; i < mParams.Length; i++)
{
mParams[i] = (Param)Params[i].Clone();
}
m.Params = mParams;
return m;
}
#endregion
}
/// 方法参数配置
/// </summary>
[Serializable]
public class MethodParams : ICloneable
{
/// <summary>
/// 类型全称
/// </summary>
[XmlAttribute(AttributeName = "type")]
public string TypeFullName { get; set; }
/// <summary>
/// 方法名
/// </summary>
[XmlAttribute(AttributeName = "method")]
public string MethodName { get; set; }
/// <summary>
/// 参数集合
/// </summary>
public Param[] Params { get; set; }
/// <summary>
/// 获取参数集合中特定名称的参数
/// </summary>
/// <param name="paramName">参数名称</param>
/// <returns></returns>
public Param GetParam(string paramName)
{
Param p = null;
if (Params != null && Params.Length > 0)
{
foreach (Param pi in Params)
{
if (pi.Name == paramName)
{
p = pi;
break;
}
}
}
return p;
}
/// <summary>
/// [穷举]获取所有方法最个可能参数的的情况(各个参数可能情况的乘积)
/// </summary>
/// <returns></returns>
public MethodParams[] GetAvailableMethodParams()
{
List<MethodParams> mparmList = new List<MethodParams>();
bool addDefaultMethodParams = false;
List<Param> baseParams = new List<Param>();
foreach (Param pm in Params)
{
foreach (Param rpm in Params)
{
if (rpm.Name == pm.Name)
{
#region 当前参数
int totalCount = rpm.GetUsableValueCount();
//Console.WriteLine(rpm.Name + " : " + totalCount);
if (totalCount == 1)
{
if (rpm.IsOptional) baseParams.Add(rpm);
if (!addDefaultMethodParams)
{
MethodParams defaultMethodParams = new MethodParams();
defaultMethodParams.TypeFullName = TypeFullName;
defaultMethodParams.MethodName = MethodName;
defaultMethodParams.Params = Params;
mparmList.Add(defaultMethodParams);
addDefaultMethodParams = true;
}
}
else
{
#region 穷举参数的所有可能值清况
List<Param> rpmAvailableList = new List<Param>();
foreach (Param rpmAvailable in Params)
{
if (rpmAvailable.Name != rpm.Name)
{
rpmAvailableList.Add(rpmAvailable);
}
}
rpmAvailableList.Add(null);
int t = mparmList.Count;
//Console.WriteLine("Available Count:" + t);
for (int i = 0; i < totalCount; i++)
{
Param parmAvailale = (Param)rpm.Clone();
parmAvailale.Value = rpm.GetUsableValue(i).ToString();
rpmAvailableList[rpmAvailableList.Count - 1] = parmAvailale;
//小于一个单位
if (t < 1)
{
#region 基数为1单位时,加法即乘法。
MethodParams mparmAvailale = new MethodParams();
mparmAvailale.TypeFullName = TypeFullName;
mparmAvailale.MethodName = MethodName;
mparmAvailale.Params = rpmAvailableList.ToArray();
//Console.WriteLine("< 1 Unit,ADD:---" + parmAvailale.Value);
mparmList.Add(mparmAvailale);
#endregion
}
else
{
for (int k = 0; k < t; k++)
{
#region 乘以基数运算
MethodParams mparmInList = mparmList[k];
//Console.WriteLine(k);
bool blnAddNewMethodParam = true;
#region 检查是否有重复的方法参数定义
foreach (Param parminList in mparmInList.Params)
{
if (parminList.Name == rpm.Name)
{
if (parminList.Value == parmAvailale.Value)
{
blnAddNewMethodParam = false;
//Console.WriteLine("Not ADD:" + parmAvailale.Value);
break;
}
}
}
#endregion
if (blnAddNewMethodParam == true)
{
Param[] upataParams = new Param[mparmInList.Params.Length];
#region DeepClone
for (int u = 0; u < upataParams.Length; u++)
{
Param pu = (Param)mparmInList.Params[u].Clone();
upataParams[u] = pu;
}
#endregion
#region Update
int idx = 0;
foreach (Param parminListUpdate in mparmInList.Params)
{
if (parminListUpdate.Name == rpm.Name)
{
upataParams[idx].Value = parmAvailale.Value;
break;
}
idx++;
}
#endregion
MethodParams mparmNew = new MethodParams();
mparmNew.TypeFullName = TypeFullName;
mparmNew.MethodName = MethodName;
mparmNew.Params = upataParams;
//Console.WriteLine("Update:---" + parmAvailale.Value);
mparmList.Add(mparmNew);
}
#endregion
}
//Console.WriteLine("-----" + t + "*" + (i+1).ToString());
}
}
#endregion
}
if (rpm.IsOptional)
{
#region 该参数可选情况
if (mparmList.Count < 1)
{
List<Param> rpmOptionList = new List<Param>();
foreach (Param rpmOpt in Params)
{
if (rpmOpt.Name != rpm.Name)
{
rpmOptionList.Add(rpmOpt);
}
}
MethodParams mparmOpt = new MethodParams();
mparmOpt.TypeFullName = TypeFullName;
mparmOpt.MethodName = MethodName;
mparmOpt.Params = rpmOptionList.ToArray();
mparmList.Add(mparmOpt);
}
else
{
#region X2 可选操作
for (int ei = 0; ei < mparmList.Count; ei++)
{
List<Param> eiOptionList = new List<Param>();
foreach (Param rpmOpt in mparmList[ei].Params)
{
if (rpmOpt.Name != rpm.Name) eiOptionList.Add(rpmOpt);
}
Param[] eiToAddArray = eiOptionList.ToArray();
if (!ExistsMethodParams(mparmList, eiToAddArray))
{
MethodParams eiParmOpt = (MethodParams)mparmList[ei].Clone();
eiParmOpt.Params = eiToAddArray;
mparmList.Add(eiParmOpt);
}
}
#endregion
}
#endregion
}
#endregion
}
}
}
if (baseParams.Count == Params.Length)
{
MethodParams baseMethodParams = new MethodParams();
baseMethodParams.TypeFullName = TypeFullName;
baseMethodParams.MethodName = MethodName;
baseMethodParams.Params = baseParams.ToArray();
mparmList.Add(baseMethodParams);
}
return mparmList.ToArray();
}
/// <summary>
/// 检查所有的参数集合中是否存在指定的方法参数
/// </summary>
private bool ExistsMethodParams(List<MethodParams> plist, Param[] MethodParamsArray)
{
bool exists = false;
for (int ichk = 0; ichk < plist.Count; ichk++)
{
Param[] toCHKArray = plist[ichk].Params;
//参数个数不匹配
if (toCHKArray.Length != MethodParamsArray.Length)
{
continue;
}
else
{
int eqTotal = 0;
foreach (Param chkParam in toCHKArray)
{
for (int eic = 0; eic < MethodParamsArray.Length; eic++)
{
if (chkParam.Name == MethodParamsArray[eic].Name
&& chkParam.Value == MethodParamsArray[eic].Value)
{
eqTotal++;
}
}
}
if (eqTotal == MethodParamsArray.Length)
{
exists = true;
break;
}
}
}
return exists;
}
#region ICloneable 成员
/// <summary>
/// 创建作为当前实例副本的新对象。
/// </summary>
/// <returns>作为此实例副本的新对象。</returns>
public object Clone()
{
MethodParams m = new MethodParams();
m.TypeFullName = TypeFullName;
m.MethodName = MethodName;
Param[] mParams = new Param[Params.Length];
for (int i = 0; i < mParams.Length; i++)
{
mParams[i] = (Param)Params[i].Clone();
}
m.Params = mParams;
return m;
}
#endregion
}
第三部分:测试参数
代码Param /// <summary>
/// 测试参数
/// </summary>
[Serializable]
public class Param : ICloneable
{
/// <summary>
/// 参数名称
/// </summary>
[XmlAttribute(AttributeName = "name")]
public string Name { get; set; }
/// <summary>
/// 参数类型名称
/// </summary>
[XmlAttribute(AttributeName = "type")]
public string ParamType { get; set; }
/// <summary>
/// 参数的值
/// </summary>
public string Value { get; set; }
/// <summary>
/// 参数默认值
/// </summary>
public string Default { get; set; }
/// <summary>
/// 是否是可选参数
/// </summary>
[XmlAttribute(AttributeName = "optional")]
public bool IsOptional { get; set; }
/// <summary>
/// 其他可使用的测试数据,默认使用英文逗号分隔各个值。
/// <para>支持区间语法:</para>
/// <para>1.普通数字区间:1-100[;1] 即1-100的数字,1为步长。</para>
/// <para>2.普通字母区间:a-z[;1] 即a-z的字符,1为步长,结果为a,b,c,d,e,f...z。</para>
/// <para>3.带小数的区间:0.00-1.00[;0.01] 即0-1之间的两位小数,0.01为步长。</para>
/// <para>4.完整语法定义:开始-结束[;步长][填充模式,填充长度(前面至0)],[]内参数可选,默认步长为1个单位。
/// 形如:UsableValues = "125.00-124.00;0.01;[url?down-{0}.html,5]"</para>
/// </summary>
public string UsableValues { get; set; }
/// <summary>
/// 其他可使用值的分隔符
/// </summary>
[XmlAttribute(AttributeName = "split")]
public string UsableValueSplit { get; set; }
/// <summary>
/// 获取参数的强类型值
/// </summary>
/// <returns></returns>
public object GetValue()
{
if (Value == null)
{
if (Default != null) Value = Default;
}
object result = Value;
if (this.ParamType != null)
{
//XML反序列化获取参数的值
Type pType = Type.GetType(ParamType);
if (SharedGlobal.HasAttribute(pType, typeof(System.SerializableAttribute), true))
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(Value.Trim());
MethodInfo fun = typeof(SharedGlobal).GetMethod("GetObject", new Type[] { typeof(XmlDocument) });
fun = fun.MakeGenericMethod(pType);
return fun.Invoke(null, new object[] { xmlDoc });
}
else
{
result = Convert.ChangeType(result, pType);
}
}
return result;
}
/// <summary>
/// 其他可选参数值集合
/// </summary>
private object[] OtherUsableValueCollection = new Object[0];
private void BuildOtherUsableValues(string otherValueConfig, string split)
{
if (string.IsNullOrEmpty(split)) split = ",";
if (split != "-")
{
OtherUsableValueCollection = Regex.Split(otherValueConfig, Regex.Escape(split));
}
else
{
// (\-?[\d\.a-zA-Z]+)\s?\-\s?(\-?[\d\.a-zA-Z]+)(;(\-?[\d\.]+))?(;\[(.+),(\d+)\])?
// (\\-?[\\d\\.a-zA-Z]+)\\s?\\-\\s?(\\-?[\\d\\.a-zA-Z]+)(;(\\-?[\\d\\.]+))?(;\\[(.+),(\\d+)\\])?
// 1.区间开始 2.区间结束 4.步长,默认为1个单位 6.替换模型 7.匹配位数,不足填0补齐
string numPattern = "(\\-?[\\d\\.a-zA-Z]+)\\s?\\-\\s?(\\-?[\\d\\.a-zA-Z]+)(;(\\-?[\\d\\.]+))?(;\\[(.+),(\\d+)\\])?";
Match m = Regex.Match(otherValueConfig, numPattern);
if (!m.Success)
{
throw new System.Configuration.ConfigurationErrorsException("对于可用值的区间配置(-)必须指定开始和结束数字或字母");
}
else
{
//区间范围
string[] rangDat = new string[] { m.Groups[1].Value, m.Groups[2].Value };
//默认步长为1个单位,填充位数为1
double step = 1.00;
int fillLen = 1;
bool cusStepSet = false, restore2Char = false;
string fillMode = string.Empty;
#region 自动构建数字区间
if (m.Groups.Count == 8)
{
//定义了步长 m.Groups[4].Value
if (!string.IsNullOrEmpty(m.Groups[4].Value))
{
step = Convert.ToDouble(m.Groups[4].Value);
cusStepSet = true;
}
//定义了替换模型和匹配补齐规则 m.Groups[6].Value 和 m.Groups[7].Value
if (!string.IsNullOrEmpty(m.Groups[6].Value) &&
!string.IsNullOrEmpty(m.Groups[7].Value))
{
fillMode = m.Groups[6].Value;
fillLen = int.Parse(m.Groups[7].Value);
}
}
#endregion
bool isDouble = false;
int numLen = 0;
double rangeBegin, rangeEnd;
#region 设置循环区间与步长
if (Char.IsLetter(rangDat[0], 0))
{
rangeBegin = Convert.ToDouble((int)rangDat[0][0]);
rangeEnd = Convert.ToDouble((int)rangDat[1][0]);
restore2Char = true;
}
else
{
if (rangDat[0].Contains(".")) isDouble = true;
rangeBegin = double.Parse(rangDat[0]);
rangeEnd = double.Parse(rangDat[1]);
}
if (isDouble)
{
numLen = Regex.Match(rangDat[0], "\\.(\\d+)$").Groups[1].Value.Length;
if (!cusStepSet)
{
step = 1.00 / Math.Pow(10.00, Convert.ToDouble(numLen));
}
}
#endregion
//递减
if (rangeBegin.CompareTo(rangeEnd) > 0 && step > 0.00) step = 0.00 - step;
Func<bool> fFlag = new Func<bool>(delegate() { return rangeBegin <= rangeEnd; });
//是否递减
if (step < 0.00)
{
fFlag = new Func<bool>(delegate() { return rangeBegin >= rangeEnd; });
}
string strTemp = string.Empty;
List<string> strValues = new List<string>();
while (fFlag())
{
#region 循环
if (restore2Char == true)
{
if (fillMode != string.Empty)
{
strTemp = String.Format(fillMode, ((char)((int)rangeBegin)).ToString().PadLeft(fillLen, '0'));
}
else
{
strTemp = ((char)((int)rangeBegin)).ToString();
}
}
else
{
strTemp = (isDouble) ? rangeBegin.ToString("N" + numLen) : rangeBegin.ToString();
if (fillMode != string.Empty)
{
strTemp = String.Format(fillMode, strTemp.PadLeft(fillLen, '0'));
}
}
//Console.WriteLine(strTemp);
strValues.Add(strTemp);
rangeBegin += step;
#endregion
}
OtherUsableValueCollection = strValues.ToArray();
}
}
}
/// <summary>
/// 获取可用参数值的个数
/// </summary>
/// <returns></returns>
public int GetUsableValueCount()
{
if (UsableValues == null) return 1;
if (OtherUsableValueCollection.Length == 0)
{
BuildOtherUsableValues(UsableValues, UsableValueSplit ?? ",");
}
//其他可用和默认值
return OtherUsableValueCollection.Length + 1;
}
/// <summary>
/// 获取可用第N个参数
/// </summary>
/// <param name="idx">可选的参数索引</param>
/// <returns></returns>
public object GetUsableValue(int idx)
{
object result = null;
int totalCount = GetUsableValueCount();
if (totalCount > 0 && idx < totalCount)
{
if (idx == 0)
{
result = GetValue();
}
else
{
result = OtherUsableValueCollection[idx - 1];
if (this.ParamType != null)
{
result = Convert.ChangeType(result, Type.GetType(ParamType));
}
}
}
return result;
}
/// <summary>
/// 获取当前参数的值定义的字符串表示
/// </summary>
public override string ToString()
{
return string.Concat("{", string.Format("name:{0},type:{1},Value:{2},optional:{3},Default:{4},UsableValues:{5},split:{6}",
Name,
ParamType ?? "string",
Value,
IsOptional,
Default ?? "null",
UsableValues ?? "null",
UsableValueSplit ?? "\",\""),
"}");
}
#region ICloneable 成员
/// <summary>
/// 创建作为当前实例副本的新对象。
/// </summary>
/// <returns>作为此实例副本的新对象。</returns>
public object Clone()
{
Param p = new Param();
p.Name = Name;
p.ParamType = ParamType;
p.Value = Value;
p.Default = Default;
p.IsOptional = IsOptional;
p.UsableValues = UsableValues;
p.UsableValueSplit = UsableValueSplit;
return p;
}
#endregion
}
/// 测试参数
/// </summary>
[Serializable]
public class Param : ICloneable
{
/// <summary>
/// 参数名称
/// </summary>
[XmlAttribute(AttributeName = "name")]
public string Name { get; set; }
/// <summary>
/// 参数类型名称
/// </summary>
[XmlAttribute(AttributeName = "type")]
public string ParamType { get; set; }
/// <summary>
/// 参数的值
/// </summary>
public string Value { get; set; }
/// <summary>
/// 参数默认值
/// </summary>
public string Default { get; set; }
/// <summary>
/// 是否是可选参数
/// </summary>
[XmlAttribute(AttributeName = "optional")]
public bool IsOptional { get; set; }
/// <summary>
/// 其他可使用的测试数据,默认使用英文逗号分隔各个值。
/// <para>支持区间语法:</para>
/// <para>1.普通数字区间:1-100[;1] 即1-100的数字,1为步长。</para>
/// <para>2.普通字母区间:a-z[;1] 即a-z的字符,1为步长,结果为a,b,c,d,e,f...z。</para>
/// <para>3.带小数的区间:0.00-1.00[;0.01] 即0-1之间的两位小数,0.01为步长。</para>
/// <para>4.完整语法定义:开始-结束[;步长][填充模式,填充长度(前面至0)],[]内参数可选,默认步长为1个单位。
/// 形如:UsableValues = "125.00-124.00;0.01;[url?down-{0}.html,5]"</para>
/// </summary>
public string UsableValues { get; set; }
/// <summary>
/// 其他可使用值的分隔符
/// </summary>
[XmlAttribute(AttributeName = "split")]
public string UsableValueSplit { get; set; }
/// <summary>
/// 获取参数的强类型值
/// </summary>
/// <returns></returns>
public object GetValue()
{
if (Value == null)
{
if (Default != null) Value = Default;
}
object result = Value;
if (this.ParamType != null)
{
//XML反序列化获取参数的值
Type pType = Type.GetType(ParamType);
if (SharedGlobal.HasAttribute(pType, typeof(System.SerializableAttribute), true))
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(Value.Trim());
MethodInfo fun = typeof(SharedGlobal).GetMethod("GetObject", new Type[] { typeof(XmlDocument) });
fun = fun.MakeGenericMethod(pType);
return fun.Invoke(null, new object[] { xmlDoc });
}
else
{
result = Convert.ChangeType(result, pType);
}
}
return result;
}
/// <summary>
/// 其他可选参数值集合
/// </summary>
private object[] OtherUsableValueCollection = new Object[0];
private void BuildOtherUsableValues(string otherValueConfig, string split)
{
if (string.IsNullOrEmpty(split)) split = ",";
if (split != "-")
{
OtherUsableValueCollection = Regex.Split(otherValueConfig, Regex.Escape(split));
}
else
{
// (\-?[\d\.a-zA-Z]+)\s?\-\s?(\-?[\d\.a-zA-Z]+)(;(\-?[\d\.]+))?(;\[(.+),(\d+)\])?
// (\\-?[\\d\\.a-zA-Z]+)\\s?\\-\\s?(\\-?[\\d\\.a-zA-Z]+)(;(\\-?[\\d\\.]+))?(;\\[(.+),(\\d+)\\])?
// 1.区间开始 2.区间结束 4.步长,默认为1个单位 6.替换模型 7.匹配位数,不足填0补齐
string numPattern = "(\\-?[\\d\\.a-zA-Z]+)\\s?\\-\\s?(\\-?[\\d\\.a-zA-Z]+)(;(\\-?[\\d\\.]+))?(;\\[(.+),(\\d+)\\])?";
Match m = Regex.Match(otherValueConfig, numPattern);
if (!m.Success)
{
throw new System.Configuration.ConfigurationErrorsException("对于可用值的区间配置(-)必须指定开始和结束数字或字母");
}
else
{
//区间范围
string[] rangDat = new string[] { m.Groups[1].Value, m.Groups[2].Value };
//默认步长为1个单位,填充位数为1
double step = 1.00;
int fillLen = 1;
bool cusStepSet = false, restore2Char = false;
string fillMode = string.Empty;
#region 自动构建数字区间
if (m.Groups.Count == 8)
{
//定义了步长 m.Groups[4].Value
if (!string.IsNullOrEmpty(m.Groups[4].Value))
{
step = Convert.ToDouble(m.Groups[4].Value);
cusStepSet = true;
}
//定义了替换模型和匹配补齐规则 m.Groups[6].Value 和 m.Groups[7].Value
if (!string.IsNullOrEmpty(m.Groups[6].Value) &&
!string.IsNullOrEmpty(m.Groups[7].Value))
{
fillMode = m.Groups[6].Value;
fillLen = int.Parse(m.Groups[7].Value);
}
}
#endregion
bool isDouble = false;
int numLen = 0;
double rangeBegin, rangeEnd;
#region 设置循环区间与步长
if (Char.IsLetter(rangDat[0], 0))
{
rangeBegin = Convert.ToDouble((int)rangDat[0][0]);
rangeEnd = Convert.ToDouble((int)rangDat[1][0]);
restore2Char = true;
}
else
{
if (rangDat[0].Contains(".")) isDouble = true;
rangeBegin = double.Parse(rangDat[0]);
rangeEnd = double.Parse(rangDat[1]);
}
if (isDouble)
{
numLen = Regex.Match(rangDat[0], "\\.(\\d+)$").Groups[1].Value.Length;
if (!cusStepSet)
{
step = 1.00 / Math.Pow(10.00, Convert.ToDouble(numLen));
}
}
#endregion
//递减
if (rangeBegin.CompareTo(rangeEnd) > 0 && step > 0.00) step = 0.00 - step;
Func<bool> fFlag = new Func<bool>(delegate() { return rangeBegin <= rangeEnd; });
//是否递减
if (step < 0.00)
{
fFlag = new Func<bool>(delegate() { return rangeBegin >= rangeEnd; });
}
string strTemp = string.Empty;
List<string> strValues = new List<string>();
while (fFlag())
{
#region 循环
if (restore2Char == true)
{
if (fillMode != string.Empty)
{
strTemp = String.Format(fillMode, ((char)((int)rangeBegin)).ToString().PadLeft(fillLen, '0'));
}
else
{
strTemp = ((char)((int)rangeBegin)).ToString();
}
}
else
{
strTemp = (isDouble) ? rangeBegin.ToString("N" + numLen) : rangeBegin.ToString();
if (fillMode != string.Empty)
{
strTemp = String.Format(fillMode, strTemp.PadLeft(fillLen, '0'));
}
}
//Console.WriteLine(strTemp);
strValues.Add(strTemp);
rangeBegin += step;
#endregion
}
OtherUsableValueCollection = strValues.ToArray();
}
}
}
/// <summary>
/// 获取可用参数值的个数
/// </summary>
/// <returns></returns>
public int GetUsableValueCount()
{
if (UsableValues == null) return 1;
if (OtherUsableValueCollection.Length == 0)
{
BuildOtherUsableValues(UsableValues, UsableValueSplit ?? ",");
}
//其他可用和默认值
return OtherUsableValueCollection.Length + 1;
}
/// <summary>
/// 获取可用第N个参数
/// </summary>
/// <param name="idx">可选的参数索引</param>
/// <returns></returns>
public object GetUsableValue(int idx)
{
object result = null;
int totalCount = GetUsableValueCount();
if (totalCount > 0 && idx < totalCount)
{
if (idx == 0)
{
result = GetValue();
}
else
{
result = OtherUsableValueCollection[idx - 1];
if (this.ParamType != null)
{
result = Convert.ChangeType(result, Type.GetType(ParamType));
}
}
}
return result;
}
/// <summary>
/// 获取当前参数的值定义的字符串表示
/// </summary>
public override string ToString()
{
return string.Concat("{", string.Format("name:{0},type:{1},Value:{2},optional:{3},Default:{4},UsableValues:{5},split:{6}",
Name,
ParamType ?? "string",
Value,
IsOptional,
Default ?? "null",
UsableValues ?? "null",
UsableValueSplit ?? "\",\""),
"}");
}
#region ICloneable 成员
/// <summary>
/// 创建作为当前实例副本的新对象。
/// </summary>
/// <returns>作为此实例副本的新对象。</returns>
public object Clone()
{
Param p = new Param();
p.Name = Name;
p.ParamType = ParamType;
p.Value = Value;
p.Default = Default;
p.IsOptional = IsOptional;
p.UsableValues = UsableValues;
p.UsableValueSplit = UsableValueSplit;
return p;
}
#endregion
}
使用示例:
代码CollectExample static void CollectExample()
{
MethodParams mParams = ParamsBuild.ConfigInstance.GetParamConfig();
MethodParams[] allParams = mParams.GetAvailableMethodParams();
MethodParams cParams = null;
string rawRaw = string.Empty;
string currentURL = string.Empty;
using (WebClient client = new WebClient())
{
client.Encoding = Encoding.Default;
client.Headers.Add(HttpRequestHeader.UserAgent, "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; InfoPath.2; .NET4.0C; .NET4.0E)");
for (int i = 0, j = allParams.Length; i < j; i++)
{
cParams = allParams[i];
currentURL = string.Format(cParams.GetParam("url").Value, cParams.GetParam("id").Value);
Console.WriteLine(currentURL);
try
{
//下载资源
//rawRaw = client.DownloadString(currentURL);
}
catch (Exception exp)
{
Console.WriteLine(exp.Message);
}
System.Threading.Thread.Sleep(100);
if (i % 5 == 0)
{
System.Threading.Thread.Sleep(1000);
}
}
}
}
{
MethodParams mParams = ParamsBuild.ConfigInstance.GetParamConfig();
MethodParams[] allParams = mParams.GetAvailableMethodParams();
MethodParams cParams = null;
string rawRaw = string.Empty;
string currentURL = string.Empty;
using (WebClient client = new WebClient())
{
client.Encoding = Encoding.Default;
client.Headers.Add(HttpRequestHeader.UserAgent, "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; InfoPath.2; .NET4.0C; .NET4.0E)");
for (int i = 0, j = allParams.Length; i < j; i++)
{
cParams = allParams[i];
currentURL = string.Format(cParams.GetParam("url").Value, cParams.GetParam("id").Value);
Console.WriteLine(currentURL);
try
{
//下载资源
//rawRaw = client.DownloadString(currentURL);
}
catch (Exception exp)
{
Console.WriteLine(exp.Message);
}
System.Threading.Thread.Sleep(100);
if (i % 5 == 0)
{
System.Threading.Thread.Sleep(1000);
}
}
}
}
使用场景:一般可用于单元测试、数据采集等代码片段中,去年编写的博客草稿,欢迎各位拍砖~
完整及演示代码下载:https://files.cnblogs.com/ridge/ParamsBuildTest.zip

浙公网安备 33010602011771号