Home

Main behaves differently between LINQPad & LPRun

This is a follow-on from my comment to “Help! LPRun.exe exceptions not setting %errorlevel%” thread…

I ran into a strange difference between how Main behaves under LINQPad and under LPRun and I am not sure the discrepancy is intentional. It seems that you can return any type of value from Main, not just an integer, and LINQPad will still happily run it (i.e. accepts the signature of the entry-point) and displays the returned value in the Results pane. For example, if I return a sequence (an IEnumerable<> of some T) from Main then it gets displayed. LPRun, on the other hand, discards the returned value. It's as if LINQPad has a much more relaxed definition of Main than C# would accept and I was taking advantage of it until I realised that LPRun behaves differently. Since I stumbled on this by sheer accident, it makes me wonder if this is a bug or a feature. Moreover, if the issue with returning an exit code from Main ever gets fixed, I'm worried about it introducing a breaking change in my scripts.

Yet another different I've found is that I can define optional arguments on my Main, e.g.:

void Main(string[] args, int x = 10)
{
// ...
}
This works perfectly under LINQPad but LPRun breaks with an error:

ArgumentException: Object of type 'System.String' cannot be converted to type 'System.String[]'.
at System.RuntimeType.TryChangeType(Object value, Binder binder, CultureInfo culture, Boolean needsSpecialCast)
at System.RuntimeType.CheckValue(Object value, Binder binder, CultureInfo culture, BindingFlags invokeAttr)
at System.Reflection.MethodBase.CheckArguments(Object[] parameters, Binder binder, BindingFlags invokeAttr, CultureInfo culture, Signature sig)
at System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
at LINQPad.ExecutionModel.ClrQueryRunner.Run()
at LINQPad.ExecutionModel.Server.RunQuery(QueryRunner runner)

Comments

  • That behaviour is intentional. It's because there are two ways to call another script:

    - LPRun
    - Util.Run

    With Util.Run, you can pass and return richly-typed arguments, whereas with LPRun, you are restricted to passing in string[] args and returning an integer (because that's how the command-line works).

    If you want to call your script from the command-line, you should stick to the simple signature, otherwise feel free to use the full C# type system.
  • Thanks for the explanation, Joe. I guess I hadn't thought about Util.Run since I have never used or had the need for it.
Sign In or Register to comment.