Skip to content
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

Add support for 'params' method arguments #3

Open
VitaliyMF opened this issue Sep 23, 2016 · 20 comments
Open

Add support for 'params' method arguments #3

VitaliyMF opened this issue Sep 23, 2016 · 20 comments

Comments

@VitaliyMF
Copy link
Contributor

It is useful to support method calls with variable number of parameters (in c# marked as 'params').
Good example is String.Format.

@EricB85
Copy link

EricB85 commented Jul 17, 2020

It would be very useful indeed (to me anyway). Did you find how to do it?

@VitaliyMF
Copy link
Contributor Author

Real method argument is an array, so you can pass variable number of arguments by composing an array:

Format("test {0} {1}", new [] { "argument0", "argument1"} )

@EricB85
Copy link

EricB85 commented Jul 17, 2020

But how would you do a method like "DoSometing(t1,t2)" and "DoSometing(t1, t2, t3, t4)" ?

@VitaliyMF
Copy link
Contributor Author

It looks like it is possible to handle "params" argument in the same way as it works in C# (when compiler automatically converts method arguments into array): https://stackoverflow.com/questions/627656/determining-if-a-parameter-uses-params-using-reflection-in-c

To handle "params" method argument some modifications are needed here: https://github.com/nreco/lambdaparser/blob/master/src/NReco.LambdaParser/InvokeMethod.cs

@microspud
Copy link
Contributor

I have added support for "Optional" parameters into my InvokeMethod.cs. If its useful I will try and extract it into a pull request based on the latest source, add unit tests etc. AFAIK it didn't break anything. Params would also be very useful, I may try to implement that.

Also another thing that I want to do is support the setting of properties / write fields as well as get / read. I propose that could be done by discriminating between == and =. I understand its pushing the boundaries of what this library is supposed to be however IMO there is not too much holding it back from being a full interpreter for use with rules engines and the likes. Maybe we can add settings to allow disallow this behaviour if security is a concern. We could even add attributes that can decorate api to control access to members?

@VitaliyMF
Copy link
Contributor Author

I have added support for "Optional" parameters into my InvokeMethod.cs. If its useful I will try and extract it into a pull request based on the latest source, add unit tests etc. AFAIK it didn't break anything. Params would also be very useful, I may try to implement that.

This sounds good! Only notice, please ensure that "Optional" parameters don't break compatibility with legacy .NET versions. It might be possible that "Optional" parameters can be supported only in "netstandard2.0" build, this is not a problem - simply use conditional compilation to exclude this enhancement from legacy builds ("netstandard1.3" and "net45").

Support of "params" might be even more useful than "Optional" parameters. Your PR is very welcome!
Please consider this policy that I always keep in mind for libs maintained by me:

  • backward compatibility is top priority. Code is changed only when there is technical need for that change (no go: "refactoring for fun", "code reformatting", etc). Users of NReco.LambdaParser should not afraid to upgrade and break their projects. Expressions parsing may be very sensitive, and incompatibility in expressions may simply break the app.
  • try to change existing code as little as possible, this simplifies changes review both by me and by lib users, when they check what is actually changed before upgrade
  • any change / bugfix should be covered by the unit test. Say, if this is a new bug, a test that reproduces it should be added first, then a bugfix that makes this test green.

Regarding

Also another thing that I want to do is support the setting of properties / write fields as well as get / read.

I think this might be not so easy to implement "setters" as it sounds. You're right that most users of the parser, most likely, don't need that and more than that, this capability can be potentially dangerous (so it is 100% should be controlled via option and disabled by default).

Take a look to this issue about local variables: #42
It already introduces "set" syntax as var a = [expr]; (note - it is disabled by default for full backward compatibility) which most likely can be extended to support field/property/indexer "setters".
BTW, you should be able to call property/indexer setter even now smth like var a = myObj.set_MyProperty(5); -- I didn't tested that, but potentially it should work! Even if not (because setter method returns void) this can be easily fixed. Maybe it would be enough to use this hack for your purposes?

@microspud
Copy link
Contributor

Thank you for your reply. Ok I will set about isolating the changes into the new version 1.1,
I will double check but I'm pretty sure optional parameters via reflection (parameterinfo etc) go back as far as dot net framework 1.1 so we should be ok.

Really good news about the new local variables option. I think that will solve most if not all of our requirements so thank you.

@microspud
Copy link
Contributor

microspud commented Dec 9, 2023

Hi, I have coded the param feature tonight and it appears to work fine. I have tested several different scenarios with different types, mixed types etc and all appears to work fine including Format (via a proxy call in the test object). I will create a separate pull request for it for review.

One note is that to avoid code duplication I did extract a couple of segments of code into private functions. We could inline these if you think performance could be impacted slightly. Let me know what you think.

microspud pushed a commit to microspud/lambdaparser that referenced this issue Dec 9, 2023
@hzy-6
Copy link

hzy-6 commented Jan 26, 2024

Params does not support

SDK:Net7.0

image
image

@VitaliyMF
Copy link
Contributor Author

@hzy-6 to enable support of 'params' and optional parameters you need to replace default InvokeMethod with OptionsParamsInvokeMethod:

var lambdaParser = new LambdaParser(OptionsParamsInvokeMethod.Instance);

@hzy-6
Copy link

hzy-6 commented Jan 26, 2024

May I ask how to implement this sum function

image

@microspud
Copy link
Contributor

@hzy-6 I cant see what is in your GetContext() method but you need to add an instance of your Funcs class with a name such as "f" to the context object.

Then in your expression use "f.sum(1,2,3...)

@VitaliyMF
Copy link
Contributor Author

@hzy-6

	public class Funcs {
		public object Sum(params object[] args) {
			decimal res = 0;
			foreach (var a in args)
				res += Convert.ToDecimal(a);
			return res;
		}
	}

	var lambdaParser = new LambdaParser(OptionsParamsInvokeMethod.Instance);
	var varContext = new Dictionary<string, object>();
	varContext["f"] = new Funcs();
	Assert.Equal(6M, lambdaParser.Eval("f.Sum(1,2,3)", varContext));

@hzy-6
Copy link

hzy-6 commented Jan 26, 2024

I hope there is no "f."

@hzy-6
Copy link

hzy-6 commented Jan 26, 2024

Hope to adapt to existing formula libraries
image

@VitaliyMF
Copy link
Contributor Author

I hope there is no "f."

No, currently "params" are supported only for object's method invocation, not for delegates.
"sum" can be a delegate, but delegates are invoked differently in LambdaParameterWrapper.InvokeDelegate method.

@microspud I didn't tested this yet, but technically delegate declarations also may have params for instance:

public delegate object SumFunc(params object[] args);

so, potentially, we can also add support for "params" in delegates by replacing deleg.DynamicInvoke(resolvedArgs) with IInvokeMethod.InvokeDelegate (that can be added into our IInvokeMethod interface). What do you think?

@hzy-6
Copy link

hzy-6 commented Jan 26, 2024

Thank you. What exactly should we do

@hzy-6
Copy link

hzy-6 commented Jan 26, 2024

Unable to intercept

image

@VitaliyMF
Copy link
Contributor Author

Unable to intercept

To support "params" for delegates invocations NReco.LambdaParser code needs to be changed, you cannot achieve that in the current version.

If you know what to do, you can make necessary changes and propose a PR. Otherwise, you need to wait until @microspud or me finds a time for this change.

@hzy-6
Copy link

hzy-6 commented Jan 26, 2024

Okay, thank you. I'll learn it first. I hope we can release the function interceptor later

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants