有了前面的铺垫,要加入功能就很简单了,下面我们加入对函数的支持
一、函数的要点有3个
1. 名称: 没有名字可程序就不能识别了,呵呵
例: Sin, Cos, Abs 等
2. 参数:一个函数至少要有一个参数,参数必须放到括号里, 多个参数用逗号(,)分隔
3. 计算:函数必须有一个输出值
二、了解了这几点,加入函数的功能还是比较容易的
1.根据函数的要点定义基类 FunctionBase, 加入一些属性
a.名称
protected string name;
/// <summary>
/// 函数名称
/// </summary>
public string Name
{
get { return name; }
set { name = value; }
}
b.参数/// <summary>
/// 函数名称
/// </summary>
public string Name
{
get { return name; }
set { name = value; }
}
protected decimal?[] data;
/// <summary>
/// 参数数组(储存传入的参数)
/// </summary>
public decimal?[] Data
{
get { return data; }
set { data = value; }
}
protected int paramCount;
/// <summary>
/// 指明参数的个数
/// </summary>
public int ParamCount
{
get { return paramCount; }
}
c. 计算/// <summary>
/// 参数数组(储存传入的参数)
/// </summary>
public decimal?[] Data
{
get { return data; }
set { data = value; }
}
protected int paramCount;
/// <summary>
/// 指明参数的个数
/// </summary>
public int ParamCount
{
get { return paramCount; }
}
/// <summary>
/// 计算(定义为虚函数)
/// </summary>
/// <returns></returns>
public abstract object Calc();
2. 解析表达式的时候, 加入对函数的支持/// 计算(定义为虚函数)
/// </summary>
/// <returns></returns>
public abstract object Calc();
再第二章的ConvertExpression结尾,已经有对函数的支持了,贴一小段看看
default:
//数字
if (char.IsDigit(c))
{
ProcDigit(ref i, ref strExpression);
}
else //其它的字符全当成函数
{
ProcFunc(ref i, ref strExpression);
}
break;
ProcFunc 函数和其它的 ProcXXXX 函数差不多, 无非就是对字符的解析
private void ProcFunc(ref int index, ref string expression)
{
if (needOp)
throw new ExpressionException("缺少操作符", 1001);
StringBuilder str = new StringBuilder();
for (int i = index; i < expression.Length; i++)
{
char c = expression[i];
if (char.IsWhiteSpace(c) || c == '(')
{
this.needParentheses = true;
break;
}
else
{
str.Append(c);
}
index = i;
}
string strFunc = str.ToString();
//函数是否正确
if (!FuncFactory.IsValidFunc(strFunc))
throw new ExpressionException("函数名无效:" + strFunc, 2001);
else
stackOp.Push((OperatorType)FuncFactory.GetFuncIndex(strFunc));
}
{
if (needOp)
throw new ExpressionException("缺少操作符", 1001);
StringBuilder str = new StringBuilder();
for (int i = index; i < expression.Length; i++)
{
char c = expression[i];
if (char.IsWhiteSpace(c) || c == '(')
{
this.needParentheses = true;
break;
}
else
{
str.Append(c);
}
index = i;
}
string strFunc = str.ToString();
//函数是否正确
if (!FuncFactory.IsValidFunc(strFunc))
throw new ExpressionException("函数名无效:" + strFunc, 2001);
else
stackOp.Push((OperatorType)FuncFactory.GetFuncIndex(strFunc));
}
3. 修改 CalcOperator 函数, 加入对函数的计算
if (IsBaseOperator(op))
{
//第二章中的基本四则运算, 代码可参见第二章
}
else if (IsFunc(op))
{
FunctionBase func = FuncFactory.GetFunc((int)op);
if (func == null)
throw new ExpressionException("不可识别的函数名.");
else
{
func.Data = data;
try
{
return func.Calc();
}
catch (Exception ex)
{
throw new ExpressionException("函数计算出错:" + ex.Message, 9000);
}
}
}
三、编写具体的函数{
//第二章中的基本四则运算, 代码可参见第二章
}
else if (IsFunc(op))
{
FunctionBase func = FuncFactory.GetFunc((int)op);
if (func == null)
throw new ExpressionException("不可识别的函数名.");
else
{
func.Data = data;
try
{
return func.Calc();
}
catch (Exception ex)
{
throw new ExpressionException("函数计算出错:" + ex.Message, 9000);
}
}
}
a . 函数工厂类 FuncFactory , 根据函数名称返回具体的函数类, 略。。。
b. 编写一个 sqrt 函数,作为实例,可自行添加任意函数
/// <summary>
/// 开平方
/// </summary>
public class FuncSQRT : FunctionBase
{
public FuncSQRT()
{
//参数名称和参数个数一定要设置正确
//否则在解析的时候会出错
paramCount = 1;
name = "SQRT";
}
/// <summary>
/// 计算
/// 函数类实现这一步就行了, 简单吧
/// </summary>
/// <returns></returns>
public override object Calc()
{
if (data[0] == null)
return DBNull.Value;
return Math.Sqrt((double)data[0]);
}
}
/// 开平方
/// </summary>
public class FuncSQRT : FunctionBase
{
public FuncSQRT()
{
//参数名称和参数个数一定要设置正确
//否则在解析的时候会出错
paramCount = 1;
name = "SQRT";
}
/// <summary>
/// 计算
/// 函数类实现这一步就行了, 简单吧
/// </summary>
/// <returns></returns>
public override object Calc()
{
if (data[0] == null)
return DBNull.Value;
return Math.Sqrt((double)data[0]);
}
}
PS:前面有个朋友说缺少幂运算, 呵呵, 加上这个很简单
看看加入了函数和幂运算的效果 :)
下载程序