Closed kaifuzi closed 3 years ago
Custom functions are supported: Just call the EvaluationContext.AddFunction()
method. You can find one example in the Simple Usage Scenario, where the custom function neg
is added. You can also look at the implementation of the Load*Package()
methods to see more examples. AddFunction()
takes a FunctionHandle
class, which can be constructed with a delegate, or a MethodInfo
. For convenience, delegates and method infos are casted implicitly into a FunctionHandle
. The method info can point to a static method or an instance method. If it points to an instance method, the FunctionHandle
also needs a target object, where the method should be called on.
A major limitation is however, that generic methods can not be added as custom functions. Your IIF()
function might be such a case. I tried to implement the mechanics of generic functions, but the implementation grow to complex. That is why I implemented the if()
function directly in the system. As a way out, I could make the name of the if()
function configurable.
I am afraid, operators can not be added, because they have a more complicated syntactic context and must be handled by precedence correctly. If you have suggestions for additional operators, I am happy to consider them to be implemented. But I will not likely change the meaning of already existing operator symbols or add alias symbols. Because that would either break compatibility with existing users or deviate from my goal of keeping the language simple.
Here is what I did:
// Handle special function
if (expression.IndexOf("IIF(", StringComparison.InvariantCultureIgnoreCase) >= 0)
{ expression = Regex.Replace(expression, Regex.Escape("IIF("), "IF(", RegexOptions.IgnoreCase); }
evalContext.AddFunction("CEILING", (Func<Double, Double>)(v => Math.Ceiling(v))); //Can be Double or Decimal, but Double is enough in here
For IIF
, I just replace it by IF
, it's not very safe, but it's a simple soltion for now. After you make the if()
function configurable, I will change this solution.
For CEILING
, it works perfectly with AddFunction
!
I fully agree with you to keep Mastersign.Expressions simple and easy to use!
In the upcoming verion 0.6 you can set the name of the conditional function as follows:
var context = new EvaluationContext
{
Options = new LanguageOptionsBuilder()
.WithConditionalName("iif")
.IgnoreFunctionNameCase()
.Build(),
};
you can check it out already by checking out the current master.
If I use .WithConditionalName("iif")
, does if
still work?
No, the conditional function can only have one name.
I download the master branch and test, I found I only can make iif
or if
working. I want to use if
as condition as normal, but I also want to it can support iif
for legacy reason.
Maybe this request is not common, if it's hard or it will break your code structure, I think can you give up it. Thanks!
I actually do not want to support two names for the same integrated function for simplicity reasons. It would be bad hygene for the expression code, if you could use two different names for something essential as the integrated conditional function.
Yes, you are right!
Beucase I changed from DataColumn.Expression to more powerful Mastersign.Expressions, iif
is a legacy condition name.
Then as you said, only keep one name for same integrated function, it's more clear and simple.
Can we close this issue after the release of 0.6.0?
Yes, we can close this issue for 0.6.0.
Is it possible to add customer operation & function? Becuase I have "IIF"(from DataColumn.Expression) and "Ceiling"(from NCalc), I want Mastersign.Expressions can be compatible with them, other wise I have to modify all formulas...