ExpressionTreeToString
ExpressionTreeToString copied to clipboard
`ref` and `out` modifiers for C# and VB code formatters
For C#, ref and out are required in both the parameter declaration and the method call. I think we're already handling the parameter declaration, but if the method call expects a ref or out parameter, that modifier should be written.
For VB, out parameters ought to be decorated with the appropriate attribute in the parameter declaration. Calls don't require any special syntax.
There are two areas of concern:
- How do we render a call to a method which takes a
reforoutparameter? Action...andFunc...don't haverefandoutparameters. How do we render aLambdaExpressionon a custom delegate type, which does havereforoutparameters?
There is a significant issue here. At least for the C# writer, when rendering a ParameterExpression that's an argument to a method call, that is where we have to decide whether to output ref or out. But at that point, we don't know what the method signature looks like, or even if we're within a method call.
The solution is to create a custom expression type for ref-rendered parameters, and wrap the original ParameterExpression. This expression type could be handled at the BuiltinWriterVisitor level.
See also #35, for a similar discussion WRT parameter vs parameter declaration, and metadata for block expression.
This would be a breaking change for any derived visitors (admittedly, I'm not sure if there are any...), so we're holding off on this for 4.0.
Commenting out relevant tests in source, and storing the results here:
C# results:
---- VBCompiler.PassRef
(int i) => Dummy.DummyMethodWithRef(ref i)
---- VBCompiler.PassOut
(int i) => Dummy.DummyMethodWithOut(out i)
---- VBCompiler.PassRefField
(Dummy2 d) => Dummy.DummyMethodWithRef(ref d.Data)
---- VBCompiler.PassOutField
(Dummy2 d) => Dummy.DummyMethodWithOut(out d.Data)
---- VBCompiler.PassRefClosureVariable
() => Dummy.DummyMethodWithRef(ref i)
---- VBCompiler.PassOutClosureVariable
() => Dummy.DummyMethodWithOut(out i)
---- CSCompiler.PassRef
(int i) => Dummy.DummyMethodWithRef(ref i)
---- CSCompiler.PassOut
(int i) => Dummy.DummyMethodWithOut(out i)
---- CSCompiler.PassRefField
(Dummy2 d) => Dummy.DummyMethodWithRef(ref d.Data)
---- CSCompiler.PassOutField
(Dummy2 d) => Dummy.DummyMethodWithOut(out d.Data)
---- CSCompiler.PassRefClosureVariable
() => Dummy.DummyMethodWithRef(ref i)
---- CSCompiler.PassOutClosureVariable
() => Dummy.DummyMethodWithOut(out i)
---- FactoryMethods.OutParameter
(ref int $var0) => $var0
---- FactoryMethods.RefParameter
(ref int $var0) => $var0
---- FactoryMethods.PassRef
Dummy.DummyMethodWithRef(ref $var0)
---- FactoryMethods.PassOut
Dummy.DummyMethodWithOut(out $var0)
---- FactoryMethods.PassRefField
Dummy.DummyMethodWithRef(ref #Dummy2.Data)
---- FactoryMethods.PassOutField
Dummy.DummyMethodWithOut(out #Dummy2.Data)
and VB results. As noted, VB doesn't require ByRef at the call site, so only those test results are included here:
---- FactoryMethods.OutParameter
Function(ByRef $var0 As Integer) $var0
---- FactoryMethods.RefParameter
Function(ByRef $var0 As Integer) $var0