-
-
Notifications
You must be signed in to change notification settings - Fork 364
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
'Unused Parameters' make lambda compilation fail #60
Comments
Hello Steven, Can you elaborate more the expression: "I did use it, but the parser didn't notice"? thanks |
Hi David, Here you go 😄 class GlobalContext
{
public int NumericProperty { get; set; }
}
[Test]
public void Test_Github_Issue_60()
{
var parameter = new Parameter("value", typeof(GlobalContext));
var interpreter = new Interpreter(InterpreterOptions.DefaultCaseInsensitive);
//Reference our parameter
interpreter.Reference(typeof(GlobalContext));
//Pretend GlobalContext is our current context and reference property types.
var knownTypes = new HashSet<Type>(interpreter.ReferencedTypes.Select(x => x.Type));
foreach (var property in typeof(GlobalContext).GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
var propExpr = Expression.Property(parameter.Expression, property);
interpreter.SetExpression(property.Name, propExpr);
if (knownTypes.Add(property.PropertyType))
interpreter.Reference(property.PropertyType);
}
//this line crashes because of the ctor in Lambda.cs
//var lambdaExpression = Expression.Lambda(_expression, _parserArguments.UsedParameters.Select(p => p.Expression).ToArray());
//UsedParameters is empty because our parameter "value" is not used directly.
//NumericProperty does reference it, though, since it's a property of value.
//Other than crashing, which is sad, it seems like in this specific example the expression being compiled who's responsible for the crash, is not used since we're using a typed delegate compile below.
var script = interpreter.Parse("NumericProperty > 3", typeof(bool), parameter);
//However, this does work as expected since we're actually using the value parameter here.
//var script = interpreter.Parse("value.NumericProperty > 3", typeof(bool), parameter);
//This one works because it uses _parserArguments.DeclaredParameters instead of _parserArguments.UsedParameters
var @delegate = script.Compile<Func<GlobalContext, bool>>();
var context = new GlobalContext
{
NumericProperty = 5
};
var result = @delegate(context);
Assert.AreEqual(true, result);
} |
Thanks, now the problem is clear. Your scenario is interesting but for now not officially supported. It is related to issue #18, and probably your solution is an useful hint on how to solve this scenario. Unfortunately changing A quick solution is to write expression with an explicit context, like
Can be a valid option for your scenario? Eventually this can also be done at runtime, not very clean but it should be quite easy to prepend |
Thanks for looking it over. I had considered your solution before, having the users type out "value.NumericProperty" instead, but I'm trying to put this into place into an existing API and trying to break as little as possible. Worst case I will go with that option! Definitely not the worst thing in the world. We are currently using Roslyn (why i'm trying to simulate context in the first place!) and it worked well, but it was a lot slower to eval our little snippets and we had a ton of assemblies loaded into memory in no time. So I'm trying to move away from that. I also considered manually prepending "value." on all known properties when I receive the input, but that's a path I'd rather not take as I'll never feel 100% sure it will be correct every single time. For now, I've forked the repo and changed the crashing line to new Lazy<Delegate>(() =>{
var lambdaExpression = Expression.Lambda(_expression, _parserArguments.UsedParameters.Select(p => p.Expression).ToArray());
return lambdaExpression.Compile();
); The delegate isn't ever called in my case, which is good enough for now, since I'm using: script.Compile<Func<GlobalContext, bool>>(); (In other words, I could easily comment out the whole part in my very specific case and everything would still work just fine) However, since Anyway, it's definitely up to you to chose what you do with this. I just figured I'd report it since typed |
Hi,
Just discovered this project and I was playing around with it. I found a minor issue and figured I'd report it.
Basically I have a set of scripts that all run on an instance that I pass as parameter. On startup, I create an interpreter and try to simulate context by adding all the properties of said parameter.
Eventually, I will generate a compiled lambda.
The
Parse
method will fail, because of the following line in the constructor ofLambda.cs
UsedParameters
is empty, because I haven't actually used the parameter, I've used properties of said parameter. (meaning I did use it, but the parser didn't notice)After reading the note that it's not really needed to compile the lambda there if you're going to compile a typed one later, I changed the code there to a
Lazy<Delegate>
instead, which was enough to make things work out for me. However, when compiling a typed lambda, I noticed you used the following code:Here
DeclaredParameters
is used instead ofUsedParameters
.Shouldn't this also be the case for the lambda compilation in the ctor of
Lambda.cs
?The text was updated successfully, but these errors were encountered: