﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>IT博客-玄铁剑-文章分类-.net3.0</title><link>http://www.cnitblog.com/MartinYao/category/5378.html</link><description>成功的途径：抄，创造，研究，发明...</description><language>zh-cn</language><lastBuildDate>Mon, 26 Sep 2011 12:55:54 GMT</lastBuildDate><pubDate>Mon, 26 Sep 2011 12:55:54 GMT</pubDate><ttl>60</ttl><item><title>math / function / boolean /string expression evaluator</title><link>http://www.cnitblog.com/MartinYao/articles/47751.html</link><dc:creator>玄铁剑</dc:creator><author>玄铁剑</author><pubDate>Thu, 07 Aug 2008 09:32:00 GMT</pubDate><guid>http://www.cnitblog.com/MartinYao/articles/47751.html</guid><wfw:comment>http://www.cnitblog.com/MartinYao/comments/47751.html</wfw:comment><comments>http://www.cnitblog.com/MartinYao/articles/47751.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/MartinYao/comments/commentRss/47751.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/MartinYao/services/trackbacks/47751.html</trackback:ping><description><![CDATA[<p>Introduction</p>
<p>I've come across several expression evaluators on this site. They utilize several clever ideas to implement them, but each of them had their "gotchas". I needed one that was flexible (handled more than one data type), that didn't compile code (too slow and wasted resources), that worked (one couldn't handle <em>any</em> unary operator), and could be easily adapted for other needs.</p>
<p>Thus, I've developed a set of simple classes called <code>ExpressionEval</code> and <code>FunctionEval</code>. These evaluators handle numeric, string, boolean, and datetime datatypes, and they support all the unary and binary operators available in C#. They also support functions (through the utilization of <code>FunctionEval</code> class) and have the ability to add custom functions by attaching an event handler that fires when a function name is not found.</p>
<h2>About the project files</h2>
<p>Included in the project zip(s) are the <em>.cs</em> files that implement regular expressions, expression evaluation, and function evaluation. Also included is a console based tester application that will allow you to enter and manually test particular expressions.</p>
<p>Simply select the version of the project (VS 2005 or 2003) from the versions above.</p>
<h2>API</h2>
<p>The API is really simple. You have two main classes: <code>ExpressionEval</code>, and <code>FunctionEval</code>. Both utilize each other to evaluate functions in an expression, or expressions in function parameters.</p>
<p><code>ExpressionEval</code> has a default constructor and a special constructor to initialize the <code>Expression</code> property. Everything pretty much centers around the <code>Expression</code> property, the <code>SetVariable</code> and <code>ClearVariable</code> methods, the <code>AdditionalFunctionEventHandler</code> event, and the <code>Evaluate()</code> method. There are also some special evaluate methods (i.e. <code>EvaluateBool()</code>) that return a specific data type.</p>
<p>The first time <code>Evaluate()</code> is called, the <em>object</em> creates a graph of the expression to improve performance during subsequent calls of the <code>Evaluate()</code> method. However, if the <code>Expression</code> property changes, it will release the graph and form a new one the next time <code>Evaluate()</code> is called. Therefore, if you are using a consistent expression with changing values, use the <code>SetVariable</code> method so that it will not destroy the graph for the expression.</p>
<p><code>FunctionEval</code> has a default constructor and a special constructor to initialize the <code>Expression</code> property. Calling <code>Evaluate()</code> will cause the object to find the first function in the <code>Expression</code> property and return its evaluation. Calling the <code lang=cs><span class=code-keyword>static</span></code> (or <code lang=vbnet><span class=code-keyword>Shared</span></code> in VB) <code lang=cs>Replace(<span class=code-keyword>string</span> strInput)</code> will cause the object to find all the functions in the input string, and replace them with their evaluations in the output (returned) string. (<strong>Note</strong>: I added a non-static parameter-less <code>Replace()</code> method that does the same thing, but it uses the <code>Expression</code> property as the source string.)</p>
<p>Both the <code>ExpressionEval</code> class and the <code>FunctionEval</code> class have a <code lang=cs><span class=code-keyword>public</span></code> event for handing custom functions. This event fires if a function name in the expression string has no built-in function associated. The event is named <code>AdditionalFunctionEventHandler</code>.</p>
<h2>Expression strings</h2>
<p>Expression strings are easy to construct. Standard operator precedence applies. (See C# documentation) Parenthesis work. The !, -, and ~ unary operators are functional. To call a function in the expression string use the following syntax: <code>$functioname(param1, param2, ...)</code>.</p>
<p>To get a list of the built-in functions, look at the <code>ExecuteFunction</code> method in <em>FunctionEval.cs</em>.</p>
<p>Here are some examples of expression strings:</p>
<p>(1 + 1) * 17 / 3</p>
<p>$now() &gt;= $today()</p>
<p>$pi() == $e()</p>
<p>"Today is " + $fmtdate($today(), "dddd, MMMM d, yyyy")</p>
<p>@(Variable1) == @(Variable2)</p>
<p>!true == false</p>
<ul>
    <li>Valid unary operators: <code>-</code>, <code>!</code>, <code>~</code>.
    <li>Valid binary operators: <code>*</code>, <code>/</code>, <code>%</code>, <code>+</code>, <code>-</code>, <code><span class=code-keyword>&lt;</span></code>, <code><span class=code-keyword>&lt;</span>=</code>, <code><span class=code-keyword>&gt;</span></code>, <code><span class=code-keyword>&gt;</span>=</code>, <code>==</code> (also <code>=</code>), <code>!=</code>, <code>&amp;</code>, <code>^</code>, <code>!</code>, <code>&amp;&amp;</code>, <code>||</code>.
    <li>Parenthesis are evaluated first.
    <li>E-notation (<code><span class=code-digit>7</span>.511E-<span class=code-digit>10</span></code>) is allowed for numbers and...
    <li>Hexadecimal as well (<code>0xaaf1</code>).
    <li>Expressions in the form @dt(mm/dd/yyyy hh:mm:ss (AM/PM)) will return a datetime datatype.
    <li>Expressions in the form @ts([d.]h:m[:s[.ms]]) will return a timespan datatype. tokens in [] are optional.
    <li>Expressions in the form @(VariableName) will attempt to look up a variable set by <code>SetVariable</code>. </li>
</ul>
<h2>Sample code</h2>
<p>In the unit test project, you will see a lot of sample expressions. Here are some example codes for usage:</p>
<h4>Construction and evaluation</h4>
<pre lang=cs>ExpressionEval expr = <span class=code-keyword>new</span> ExpressionEval(<span class=code-string>"</span><span class=code-string>1+1"</span>);
<span class=code-keyword>object</span> val = expr.Evaluate();</pre>
<h4>Creating a custom function handler</h4>
<div class=precollapse id=premain1 style="WIDTH: 100%"><img id=preimg1 style="CURSOR: pointer" height=9 src="http://www.codeproject.com/images/minus.gif" width=9 preid="1"><span id=precollapse1 style="MARGIN-BOTTOM: 0px; CURSOR: pointer" preid="1"> Collapse</span></div>
<pre lang=cs id=pre1 style="MARGIN-TOP: 0px"><span class=code-keyword>static</span> <span class=code-keyword>void</span> eval_AdditionalFunctionEventHandler(
<span class=code-keyword>object</span> sender, AdditionalFunctionEventArgs e)
{
<span class=code-keyword>object</span>[] parameters = e.GetParameters();
<span class=code-keyword>switch</span> (e.Name)
{
<span class=code-keyword>case</span> <span class=code-string>"</span><span class=code-string>brent"</span>:
e.ReturnValue = <span class=code-string>"</span><span class=code-string>This Library Rocks!"</span>;
<span class=code-keyword>break</span>;
<span class=code-keyword>case</span> <span class=code-string>"</span><span class=code-string>liljohn"</span>:
e.ReturnValue = <span class=code-string>"</span><span class=code-string>WWWWWWWWHHHHHAT? YEAYAH! OKAY!"</span>;
<span class=code-keyword>break</span>;
<span class=code-keyword>case</span> <span class=code-string>"</span><span class=code-string>strcat"</span>:
<span class=code-keyword>string</span> ret = <span class=code-string>"</span><span class=code-string>"</span>;
<span class=code-keyword>foreach</span> (<span class=code-keyword>object</span> parameter <span class=code-keyword>in</span> parameters)
ret += parameter.ToString();
e.ReturnValue = ret;
<span class=code-keyword>break</span>;
<span class=code-keyword>case</span> <span class=code-string>"</span><span class=code-string>setvar"</span>:
(sender <span class=code-keyword>as</span> FunctionEval).SetVariable(
<span class=code-string>"</span><span class=code-string>"</span> + parameters[<span class=code-digit>0</span>],
parameters[<span class=code-digit>1</span>]
);
<span class=code-keyword>break</span>;
}
}</pre>
<h2>Using the tester application</h2>
<p>Make sure the tester application is set as the startup project. Hit F5 to build and run. You will see a blank console screen. Type in an expression and hit Enter. Its evaluation will appear below it, otherwise an error will be displayed. Type "clr" to clear the console, and type "exit" to quit the application.</p>
<h2>Known issues</h2>
<p>There is one issue that I am aware of. If you place two binary operators in a row, no error is returned. Instead, the first in the list is used, and the rest until the right operand (w/ or w/o unary operator) are ignored.</p>
<p>Example: (1 * + -1). This will ignore '+' and execute (1 * -1).</p>
<p><strong>Note</strong>: I've improved the error handling to catch unused tokens and missing binary operators.</p>
<h2>Updates</h2>
<ul>
    <li>3/16/2006
    <ul>
        <li>Added timespan functionality and recognition: @ts([d].h:m[:s[.mmm]]). [] indicates optional components.
        <li>Added more robust error handling to catch unused tokens and missing binary operators. </li>
    </ul>
    <li>12/30/2005
    <ul>
        <li>Completely updated the code libraries (and verified that it works with the release of VS2005 Pro) and description with bug fixes and modifications that I've been sending to those who had requested for it. Also updated the custom function handling event to .NET event standards. (with sender and eventarg params) </li>
    </ul>
    <li>01/05/2005 </li>
    <ul>
        <li>Changed functionality so that upon first execution of an expression (with a created object, not the <code lang=cs><span class=code-keyword>static</span></code> (<code lang=vbnet><span class=code-keyword>Shared</span></code>) method), it parses it and creates a graph. As long as the <code>Expression</code> property is not changed, it will keep the graph and, subsequent calls to <code>Evaluate()</code> will not parse the expression, but re-execute the graph.
        <li>Also added a .NET 2003 ready <em>.zip</em> file. <br><a href="http://www.cnitblog.com/Files/MartinYao/ExpressionEval2005.zip">Packagedownload</a></li>
    </ul>
</ul>
<img src ="http://www.cnitblog.com/MartinYao/aggbug/47751.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/MartinYao/" target="_blank">玄铁剑</a> 2008-08-07 17:32 <a href="http://www.cnitblog.com/MartinYao/articles/47751.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>动态执行C# 代码</title><link>http://www.cnitblog.com/MartinYao/articles/40403.html</link><dc:creator>玄铁剑</dc:creator><author>玄铁剑</author><pubDate>Mon, 03 Mar 2008 13:18:00 GMT</pubDate><guid>http://www.cnitblog.com/MartinYao/articles/40403.html</guid><wfw:comment>http://www.cnitblog.com/MartinYao/comments/40403.html</wfw:comment><comments>http://www.cnitblog.com/MartinYao/articles/40403.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/MartinYao/comments/commentRss/40403.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/MartinYao/services/trackbacks/40403.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 1、简介能够动态执行 C# 代码是一件很酷的功能，比如，我们可以在控制台中输入一行 C# 代码，然后程序自动编译并执行这一行代码，将结果显示给我们。这差不多就是一个最简单的 C# 代码解释器了。动态执行 C# 代码又是一件很有用的功能，比如，我们可以将某些代码写在某个文件之中，由程序集在执行时进行加载，改变这些代码不用中止程序，当程序再次加载这些代码时，就自动执行的是新代码了。下面，我...&nbsp;&nbsp;<a href='http://www.cnitblog.com/MartinYao/articles/40403.html'>阅读全文</a><img src ="http://www.cnitblog.com/MartinYao/aggbug/40403.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/MartinYao/" target="_blank">玄铁剑</a> 2008-03-03 21:18 <a href="http://www.cnitblog.com/MartinYao/articles/40403.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>