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

System.PlatformNotSupportedException: Operation is not supported on this platform. #21

Open
OPunktSchmidt opened this issue Oct 28, 2019 · 5 comments

Comments

@OPunktSchmidt
Copy link

We are getting this Exception on iOs. On Android it works perfectly.

System.PlatformNotSupportedException: Operation is not supported on this platform.
at System.Linq.Expressions.Compiler.DelegateHelpers.MakeNewDelegate (System.Type[] types) <0x102e341e0 + 0x000cc> in <bb5b9967994b42d38a9a568699a96020#cbe1a7eadba32ea3a937327d324ab3f9>:0
at System.Linq.Expressions.Compiler.DelegateHelpers.MakeDelegateType (System.Type[] types) <0x102e33990 + 0x00133> in <bb5b9967994b42d38a9a568699a96020#cbe1a7eadba32ea3a937327d324ab3f9>:0
at System.Linq.Expressions.Expression.Lambda (System.Linq.Expressions.Expression body, System.String name, System.Boolean tailCall, System.Collections.Generic.IEnumerable1[T] parameters) <0x102dcea00 + 0x001bf> in <bb5b9967994b42d38a9a568699a96020#cbe1a7eadba32ea3a937327d324ab3f9>:0 at System.Linq.Expressions.Expression.Lambda (System.Linq.Expressions.Expression body, System.Boolean tailCall, System.Collections.Generic.IEnumerable1[T] parameters) <0x102dce980 + 0x00027> in <bb5b9967994b42d38a9a568699a96020#cbe1a7eadba32ea3a937327d324ab3f9>:0
at System.Linq.Expressions.Expression.Lambda (System.Linq.Expressions.Expression body, System.Linq.Expressions.ParameterExpression[] parameters) <0x102dce950 + 0x0001f> in <bb5b9967994b42d38a9a568699a96020#cbe1a7eadba32ea3a937327d324ab3f9>:0
at NReco.Linq.LambdaParser.Eval (System.String expr, System.Func2[T,TResult] getVarValue) <0x103f20090 + 0x0016b> in <ebdc87cda8e4462a9cdd9c66afdb543c#cbe1a7eadba32ea3a937327d324ab3f9>:0 at NReco.Linq.LambdaParser.Eval (System.String expr, System.Collections.Generic.IDictionary2[TKey,TValue] vars) <0x103f1ff50 + 0x00113> in <ebdc87cda8e4462a9cdd9c66afdb543c#cbe1a7eadba32ea3a937327d324ab3f9>:0
at CPM.Arda.Mobile.Questionnaire.Logic+<>c__DisplayClass0_0`1+<b__0>d[T].MoveNext () <0x103f19220 + 0x0025f> in <3200b1f0bb96405aa11baec7b62f15e6#cbe1a7eadba32ea3a937327d324ab3f9>:0
ExpressionGroudId: 7e7207be-fd8c-40e1-9b90-0ca5bad1a5ec
EvalString: (val1.Contains(val2) || val3.Contains(val4) || val5.Contains(val6) || val7.Contains(val8) || val9.Contains(val10) || val11.Contains(val12) || val13.Contains(val14) || val15.Contains(val16) || val17.Contains(val18) || val19.Contains(val20))
EvalArguments: [val17, ][val16, 8][val5, ][val15, ][val1, ][val14, 7][val13, ][val9, ][val12, 6][val11, ][val10, 5][val4, 2][val8, 4][val7, ][val3, ][val6, 3][val2, 1][val19, ][val20, 10;][val18, 9]

This is the expression string:

(val1.Contains(val2) || val3.Contains(val4) || val5.Contains(val6) || val7.Contains(val8) || val9.Contains(val10) || val11.Contains(val12) || val13.Contains(val14) || val15.Contains(val16) || val17.Contains(val18) || val19.Contains(val20))

And the values:

[val20, 10;]
[val17, 2;4;5;7;8;]
[val12, 6]
[val7, 2;4;5;7;8;]
[val2, 1]
[val19, 2;4;5;7;8;]
[val13, 2;4;5;7;8;]
[val8, 4]
[val3, 2;4;5;7;8;]
[val1, 2;4;5;7;8;]
[val5, 2;4;5;7;8;]
[val16, 8]
[val18, 9]
[val14, 7]
[val4, 2]
[val11, 2;4;5;7;8;]
[val9, 2;4;5;7;8;]
[val10, 5]
[val15, 2;4;5;7;8;]
[val6, 3]
@OPunktSchmidt
Copy link
Author

OPunktSchmidt commented Oct 29, 2019

I have created a very minimalistic repository to reproduce the error on ios. It is an Xamarin.Forms project. When you start the iOs Project a exception is thrown, on Android not.

https://github.com/OPunktSchmidt/NRecoLambdaParser.Issue21.XamarinForms

This is the relevant test code. It is placed in App.xaml.cs and is exceuted immediately on when starting the project.

    protected override void OnStart()
    {
        // Handle when your app starts

        try
        {
            NReco.Linq.LambdaParser parser = new NReco.Linq.LambdaParser(new NReco.Linq.ValueComparer() { NullComparison = NReco.Linq.ValueComparer.NullComparisonMode.Sql });

            string evalString = "(val1.Contains(val2) || val3.Contains(val4) || val5.Contains(val6) || val7.Contains(val8) || val9.Contains(val10) || val11.Contains(val12) || val13.Contains(val14) || val15.Contains(val16) || val17.Contains(val18) || val19.Contains(val20))";

            System.Collections.Generic.Dictionary<string, object> values = new System.Collections.Generic.Dictionary<string, object>();
            values.Add("val20", "10;");
            values.Add("val17", "2;4;5;7;8;");
            values.Add("val12", "6");
            values.Add("val7", "2;4;5;7;8;");
            values.Add("val2", "1");
            values.Add("val19", "2;4;5;7;8;");
            values.Add("val13", "2;4;5;7;8;");
            values.Add("val8", "4");
            values.Add("val3", "2;4;5;7;8;");
            values.Add("val1", "2;4;5;7;8;");
            values.Add("val5", "2;4;5;7;8;");
            values.Add("val16", "8");
            values.Add("val18", "9");
            values.Add("val14", "7");
            values.Add("val4", "2");
            values.Add("val11", "2;4;5;7;8;");
            values.Add("val9", "2;4;5;7;8;");
            values.Add("val10", "5");
            values.Add("val15", "2;4;5;7;8;");
            values.Add("val6", "3");

            object evalResult = parser.Eval(evalString, values);

            System.Diagnostics.Debugger.Break();
        }
        catch (System.Exception ex)
        {
            System.Diagnostics.Debugger.Break();
        }
    }

@VitaliyMF
Copy link
Contributor

Oliver, do you have any idea how to fix this incompatibility on iOS? I don't have enough expertise on .net+mobile platform. It seems LambdaParser tries to create a delegate that doesn't available on ios (Func<>?).

@OPunktSchmidt
Copy link
Author

OPunktSchmidt commented Oct 29, 2019

I haven't had a closer look. But in this depth I don't have much expertise in mobile development either.

I'll take a closer look at it. I'll be on vacation next week but I'll definitely get closer to it when I'm back in the office.

I'll keep you informed.

@OPunktSchmidt
Copy link
Author

I did some research.

"Since the iOS kernel prevents an application from generating code dynamically, Xamarin.iOS does not support any form of dynamic code generation." (https://docs.microsoft.com/bg-bg/xamarin/ios/internals/limitations)

Simple expressions like "val1 == val2" or "val1 > val2" seems to work on iOs, but more complex expressions like mine above not (there is a methode-call to "Contains in the expression).

Maybe the method-call to "Contains" requires something from namespace System.Reflection.Emit? System.Reflection.Emit is not available due to limitations under ios. I haven't worked much with dynamic code generation and System.Linq.Expressions so far so I can't say much about it.

Here are a few more interesting links:

https://stackoverflow.com/questions/19666257/how-to-compile-methodcallexpression-without-dynamicinvoke
https://stackoverflow.com/questions/24977939/what-does-expression-compile-do-on-monotouch
https://stackoverflow.com/questions/29245589/why-does-lambdaexpression-compile-work-on-ios-xamarin

I'll keep investigating...

@VitaliyMF
Copy link
Contributor

According to this documentation page, dynamic code generation is not supported on iOS; from the other side, NReco.LambdaParser uses only System.Expressions which should fallback to 'interpretation' mode on iOS. You reported that "val1 == val2" or "val1 > val2" work fine, so I may assume that an error may be caused by a bug related to the MethodCallExpression 'interpretation'.

First of all, it is good idea to test expression like "val3.Contains(val4)" with latest Xamarin platform, maybe this issue is already solved. If this doesn't help, you can modify LambdaParser class to use Expression.Compile(true) to force interpretation mode - who knows maybe this is needed for iOS.

Finally, execution of expressions on iOS 100% might be possible with own LambdaParser 'interpretation' (however this will require some development + I assume evaluation performance may be not so good).

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

2 participants