NCalc custom function referencing a Guid - c#

I'm trying to use NCalc to parse some formula from JSON files.
However sometimes I'm needing to reference another object via GUID and get that objects formula:
public class FooObject
{
NCalc.Expression expression;
double Value;
public void SetValue()
{Value = (double)expression.Evaluate()} //this throws "Value was either too large or too small for a Double."
public FooObject()
{ expression = new NCalc.Expression("TechData(b8ef73c7-2ef0-445e-8461-1e0508958a0e)")}
expression.EvaluateFunction += NCalcFunctions;
}
}
public static void NCalcFunctions(string name, FunctionArgs args)
{
if (name == "TechData") //breakpoint shows we never get this far
{
Guid techGuid = new Guid(args.Parameters[0].ToString());
TechSD techSD = _staticData.Techs[techGuid]; //this returns an TechSD object that matches the given guid.
args.Result = techSD.DataExpression;//returns an NCalc expression from the techSD
}
}
SetValue() throws an exception (Value was either too large or too small for a Double), and the custom function never gets called.
I'm suspecting it's trying to parse the GUID. Would this be correct? Is what I'm trying to do possible with NCalc? is there a better tool?

In this NCalc expression:
TechData(b8ef73c7-2ef0-445e-8461-1e0508958a0e)
GUID b8ef73c7-2ef0-445e-8461-1e0508958a0e is not parsed as a string (note there aren't single quotes), NCalc will then try to parse that expression as
b8ef73c7 variable name, undefined.
- subtraction operator.
2ef0 syntax error, it's not an identifier (it starts with a number) and also it's not a valid number (because of e it'll try to parse it as double in scientific notation but it's not valid).
...
You have to use quotes:
TechData('b8ef73c7-2ef0-445e-8461-1e0508958a0e')
Now NCalc will correctly parse this expression and your handler may simply:
var techGuid = Guid.Parse((string)args.EvaluateParameters()[0]);

Related

Check if string is numeric in one line of code

I'm working with a DNN form-building module that allows for some server-side code to be run based on a condition. For my particular scenario, I need my block of code to run if the first 4 characters of a certain form text are numeric.
The space to type the condition, though, is only one line and I believe gets injected into an if statement somewhere behind the scenes so I don't have the ability to write a mult-line conditional.
If I have a form field called MyField, I might create a simple conditional like this:
[MyField] == "some value"
Then somewhere behind the scenes it gets translated to something like if("some value" == "some value") {
I know that int.TryParse() can be used to determine whether or not a string is numeric but every implementation I've seen requires two lines of code, the first to declare a variable to contain the converted integer and the second to run the actual function.
Is there a way to check to see if the first 4 characters of a string are numeric in just one line that can exist inside an if statement?
Wrap it in an extension method.
public static class StringExtensions
{
public static bool IsNumeric(this string input)
{
int number;
return int.TryParse(input, out number);
}
}
And use it like
if("1234".IsNumeric())
{
// Do stuff..
}
UPDATE since question changed:
public static class StringExtensions
{
public static bool FirstFourAreNumeric(this string input)
{
int number;
if(string.IsNullOrEmpty(input) || input.Length < 4)
{
throw new Exception("Not 4 chars long");
}
return int.TryParse(input.Substring(4), out number);
}
}
And use it like
if("1234abc".FirstFourAreNumeric())
{
// Do stuff..
}
In response to this:
Is there a way to check to see if the first 4 characters of a string are numeric in just one line that can exist inside an if statement?
You guys don't have to make it account for anything more complicated than a positive integer.
new Regex(#"^\d{4}").IsMatch("3466") // true
new Regex(#"^\d{4}").IsMatch("6") // false
new Regex(#"^\d{4}").IsMatch("68ab") // false
new Regex(#"^\d{4}").IsMatch("1111abcdefg") // true
// in an if:
if (new Regex(#"^\d{4}").IsMatch("3466"))
{
// Do something
}
Old answer:
If you can't use TryParse, you could probably get away with using LINQ:
"12345".All(char.IsDigit); // true
"abcde".All(char.IsDigit); // false
"abc123".All(char.IsDigit); // false
If you can, here's an IsNumeric extension method, with usage:
public static class NumberExtensions
{
// <= C#6
public static bool IsNumeric(this string str)
{
float f;
return float.TryParse(str, out f);
}
// C# 7+
public static bool IsNumeric(this string str) => float.TryParse(str, out var _);
}
// ... elsewhere
"123".IsNumeric(); // true
"abc".IsNumeric(); // false, etc
"-1.7e5".IsNumeric(); // true
How about some easy LinQ?
if (str.Take(4).All(char.IsDigit) { ... }

dynamically return an object based on string description of it's type

I have a database which stores user inputs in an abstract stringified form. These user inputs have a varchar column which describes its type (string, decimal, bool, dropdown etc).
Now this get's send to the front end to display some input elements in the browser. This works great!
However since the input is so generic the value is also a varchar. The problem I am facing is that I need to do some validation on the value. (e.g. some string input have a maxLength or regex specified, a decimal can have a min and max value).
so once I get back the value the user entered it is in string format and I want to parse it to the correct native type so I can start validating it.
I would like a function which returns the parsed value in it's correct type.
so I would have a function which is something like this:
public {something here} ParseValue(InputObject object, string type) {
// parse here based on type
// InputObject has a few properties like value, min, max, regex etc
// all as a string.
// for instance if type is datetime I want to return a new object
// which has parsed the value, min and max as datetime.
// it should also be possible for the type to be decimal and min, max
// and value should be decimal in the outputObject
}
I am coming from a dynamically typed background so I have no idea how to do something like this. or even if it is possible.
any help is appreciated!
You'd be best off if you don't directly try to evaluate the type by the Database-Datatype and instead store the "real" type in a seperate DB-Column. Except if you build an association between C#-Types and Database-Types because you can do something like this then:
String val = "123";
String type = "System.Int32";
Type tempType = Type.GetType(type);
if (tempType == null)
return null;
dynamic result = Convert.ChangeType(val, tempType);
Of course this would be applicable to the boundary values also. Note that Convert.ChangeType only works for very popular Types and is not universally useable and that it throws an Exception if theres something failing which need to be catched also.
What you could do is create an interface IValidatable that defines a method like Validate(). Then you could use that as a return type. Then you just parse your value using a switch (probably delegate this to some method or class) to an implementation of IValidatable. E.g.
public interface IValidatable {
bool Validate();
}
public class ValidateableInteger : IValidatable {
private int _value;
public ValidateableInteger(int i) {
_value = i;
}
bool Validate() {
//code where you validate your integer.
}
}
Note that this is not very flexible as you only have 1 method called validate, though clearly you can define multiple more generic methods that could implement different validations.
Moreover you can create more specific interfaces for e.g. numeric types (e.g. IValidateableNumeric and ValidateableInt : IValidateableNumeric)
Note that you're basically typing your input here though, which is kindof weird and unnecessary given the fact that you can just work with typed data to begin with.
In the end I would discourage people from bypassing type system this way. In this case especially there are plenty better ways of creating form elements while using typed data (checkout the Razor template engine).

Using Sprache to parse Enums from identifiers?

I am starting to use Sprache to parse a domain specific language for math expressions. I know I can parse an identifier using something like this:
static readonly Parser<string> Identifier =
from leading in Parse.WhiteSpace.Many()
from first in Parse.Letter.Once()
from rest in Parse.LetterOrDigit.Many()
from trailing in Parse.WhiteSpace.Many()
select new string(first.Concat(rest).ToArray());
From this I want to build a parser that only succeeds if the Identifier token is one of the text values of an Enum. So say I have an Enum called Dimension, with values Dimension.Location and Dimension.Time. I want to make
static readonly Parser<Dimension> DimensionIdentifier = ...
that only succeeds if what is being parsed is an Identifier and if the token string of the identifier is one of the enum names ("Location" or "Time"), and that returns the enum value, Dimension.Location or Dimension.Time respectively. Can someone help with what is probably a simple question? Thanks!
I use the following approach:
public static Parser<TEnum> ParseEnum()
{
return Enum.GetValues(typeof(TEnum))
.Cast<TEnum>()
.Select(value => Parse.IgnoreCase(Enum.GetName(typeof(TEnum), value)).Return(value))
.Aggregate((x, y) => x.Or(y));
}
It's similar to dbugger's answer, as it's still based on Parse.Or, but written in a more functional style.
Very nice solution stolen from here...
http://www.codewise-llc.com/blog/2015/8/13/parsing-enum-values-with-sprache
Build a typed helper class to build the parser for a given enum...
public static class EnumParser<T>
{
public static Parser<T> Create()
{
var names = Enum.GetNames(typeof(T));
var parser = Parse.IgnoreCase(names.First()).Token()
.Return((T)Enum.Parse(typeof(T), names.First()));
foreach (var name in names.Skip(1))
{
parser = parser.Or(Parse.IgnoreCase(name).Token().Return((T)Enum.Parse(typeof(T), name)));
}
return parser;
}
}
Then your parser is simply this...
public static Parser<Dimension> Dimension = EnumParser<Dimension>.Create();
And some unit tests (change the class name to whatever you are using, I was using the Sprache tutorial to get started)...
[Test]
[TestCase("Time", Dimension.Time)]
[TestCase("Location", Dimension.Location)]
public void ShouldGetProperEnumValue(string enumValueName, Dimension expected)
{
var eValue = QuestionnaireGrammar.Dimension.Parse(enumValueName);
Assert.AreEqual(expected, eValue);
}
[Test]
[ExpectedException]
[TestCase("Fredo")]
public void ShouldFailIfNotInList(string enumValueName)
{
var eValue = QuestionnaireGrammar.Dimension.Parse(enumValueName);
}
Interesting library, happy to learn about it.
OK, fairly easy to chain parsers...
Created a copy of your identity parser, and called it Identifier2 to keepit clear...
public static readonly Parser<string> Identifier2 =
from leading in Parse.WhiteSpace.Many()
from first in Parse.Letter.Once()
from rest in Parse.LetterOrDigit.Many()
from trailing in Parse.WhiteSpace.Many()
select new string(first.Concat(rest).ToArray());
Then added a compound parser that takes the results of the Identifier2 parser and uses the Dimension parser...
public static readonly Parser<Dimension> IdentityDimension =
from result in Identifier2
select Dimension.Parse(result);
Though not sure what you are buying -- enum parser already seems to do everything the identifier parser does.

ToString method and return static string

Class example:
public class SomeType
{
private int type;
// some code...
public override string ToString ()
{
if (type == 1) return "One";
if (type == 2) return "Two";
}
}
Now imagine application calls thousand times ToString() method in a second.
My question is: when I use inline created string in code like something = myClass.ToString() is in every call created a new string or compiler optimize it somehow? (because strings are immutable it could be returned only referense to a static string).
And if not, should I make static private string fields and return them in ToString method for performance reasons?
Ofcourse I will test it using Stopwatch, but I need an expert answer anyway.
You're using string literals - which means you're returning a reference to the same string each time. This is guaranteed by the language specification. From section 2.4.4.5 of the C# 5 specification:
When two or more string literals that are equivalent according to the string equality operator (ยง7.10.7) appear in the same program, these string literals refer to the same string instance.
So as a simpler example:
string x = "One";
string y = "One";
Console.WriteLine(object.ReferenceEquals(x, y)); // Prints True
In your code, the ToString() method will still be called - but it won't create a new string object each time. You might consider using a switch statement instead of all those if statements, by the way.
Note that even if it did create a new string each time, creating thousands of strings per second won't make a modern CPU break into a sweat. Both the allocator and garbage collector are pretty efficient, and modern computers can do an awful lot of work in a second.

What is the simplest way to parse an expression and retrieve a parse tree?

I just want to parse simple expressions like -
IIF(FVAL(PFC) = TRUE, (IIF((ORGVAL(BAS, "2012/12/31") + ORGVAL(DA)) < 6500, (FVAL(BAS) + FVAL(DA)) * 12%, 780)), 0)`
After parsing this I should be able to know what functions contains what parameters.
|-FVAL
|-PFC
|-ORGVAL
|-BAS
|-"2012/12/31"
I'm stuck with .Net Framework 2.0, so no Linq or lambda expression goodies for me. Also I want to include the code in my custom library and not just reference it. Can anyone point me to some good library or code.
I just need to parse and not evaluate the expression and find what tokens are in use. After finding the tokens I need to change the expression string before parsing, like if the function ORGVAL is used then the parameter passed has has to be prefixed by an underscore. Like ORGVAL(BAS) will transform to ORGVAL(_BAS). Some functions can have tow parameters like ORGVAL(BAS, "2012/12/31") and this will transform to ORGVAL(_BAS, "2012/12/31")
NOTE: IF THERE ARE OTHER WAYS OF DOING IT PLEASE LET ME KNOW. I WOULD LOVE TO AVOID A PARSER AND LEXER.
If you don't mind using one of the .NET languages for the code, you can use CodeDom to compile and the code on the fly and then execute it as an in-memory-only assembly. For instance, this would be the closest approximation to the example expression you showed:
private abstract class Logic
{
protected double FVAL(object arg)
{
// put code here
return 0;
}
protected double ORGVAL(object arg)
{
// put code here
return 0;
}
protected double ORGVAL(object arg, string date)
{
// put code here
return 0;
}
public abstract double GetValue(object PFC, object BAS, object DA);
}
private class DynamicLogic : Logic
{
public override double GetValue(object PFC, object BAS, object DA)
{
return (FVAL(PFC) = true ? ((ORGVAL(BAS, "2012/12/31") + ORGVAL(DA)) < 6500 ? (FVAL(BAS) + FVAL(DA)) * .12 : 780) : 0);
}
}
private Logic GenerateLogic(string code)
{
using (CSharpCodeProvider provider = new CSharpCodeProvider())
{
StringBuilder classCode = new StringBuilder();
classCode.AppendLine("private class DynamicLogic : Logic");
classCode.AppendLine(" {");
classCode.AppendLine(" public override int GetValue(object PFC, object BAS, object DA)");
classCode.AppendLine(" {");
classCode.AppendLine(" return (" + code + ");");
classCode.AppendLine(" }");
classCode.AppendLine(" }");
CompilerParameters p = new CompilerParameters();
p.GenerateInMemory = true;
p.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location);
CompilerResults results = provider.CompileAssemblyFromSource(p, code);
return (Logic)Activator.CreateInstance(type);
if (results.Errors.HasErrors)
{
throw new Exception("Failed to compile DynamicLogic class");
}
return (Logic)results.CompiledAssembly.CreateInstance("DynamicLogic");
}
}
private double evaluate(object PFC, object BAS, object DA)
{
Logic logic = GenerateLogic("FVAL(PFC) = true ? ((ORGVAL(BAS, \"2012/12/31\") + ORGVAL(DA)) < 6500 ? (FVAL(BAS) + FVAL(DA)) * .12 : 780) : 0");
return logic.GetValue(PFC, BAS, DA);
}
EDIT: I know you said you need to actually get the expression three, itself, not just evaluate it, but I worked up the code, so I figured I'd just go ahead and post it for future passers-by.
This looks like an unpolished but complete expression parser (haven't tested it, but might be a starting point).
http://gbacon.blogspot.it/2005/09/simple-expression-parser-in-c.html
It's old but you mentioned C# 2.0 so it might be alright anyway. I'm not sure which version of C# it targets though.
What you want to do sounds a lot like parsing, so I don't think you'll have much luck finding a solution that doesn't involve parsing. If what you are trying to say is you don't want to program a parser yourself then there are several math expression parsing libraries available.
I am one of the authors of Jep.Net (http://www.singularsys.com/jep.net) which is an expression parsing component that would likely suit your needs. It is well documented, highly customizable and would definitely let you skip the tedious and error-prone process of implementing your own custom parser. And if it's not a fit for you, Googling ".net expression parsing library" will get you other libraries.
Good luck!

Categories