diff --git a/CodeConverter/CSharp/ArgumentConverter.cs b/CodeConverter/CSharp/ArgumentConverter.cs index 083801d9..f520f524 100644 --- a/CodeConverter/CSharp/ArgumentConverter.cs +++ b/CodeConverter/CSharp/ArgumentConverter.cs @@ -226,10 +226,18 @@ private CSSyntax.ArgumentSyntax CreateOptionalRefArg(IParameterSymbol p, RefKind var type = CommonConversions.GetTypeSyntax(p.Type); CSSyntax.ExpressionSyntax initializer; if (p.HasExplicitDefaultValue) { - initializer = CommonConversions.Literal(p.ExplicitDefaultValue); + if (p.ExplicitDefaultValue == null && p.Type.IsValueType && p.Type.OriginalDefinition.SpecialType != SpecialType.System_Nullable_T) { + initializer = CS.SyntaxFactory.DefaultExpression(type); + } else { + initializer = CommonConversions.Literal(p.ExplicitDefaultValue); + } } else if (HasOptionalAttribute(p)) { if (TryGetDefaultParameterValueAttributeValue(p, out var defaultValue)) { - initializer = CommonConversions.Literal(defaultValue); + if (defaultValue == null && p.Type.IsValueType && p.Type.OriginalDefinition.SpecialType != SpecialType.System_Nullable_T) { + initializer = CS.SyntaxFactory.DefaultExpression(type); + } else { + initializer = CommonConversions.Literal(defaultValue); + } } else { initializer = CS.SyntaxFactory.DefaultExpression(type); } diff --git a/CodeConverter/CSharp/ExpressionNodeVisitor.cs b/CodeConverter/CSharp/ExpressionNodeVisitor.cs index e95dc0a6..85da3798 100644 --- a/CodeConverter/CSharp/ExpressionNodeVisitor.cs +++ b/CodeConverter/CSharp/ExpressionNodeVisitor.cs @@ -471,7 +471,22 @@ public override async Task VisitParameter(VBSyntax.ParameterSy CS.SyntaxFactory.Attribute(ValidSyntaxFactory.IdentifierName("Optional")), }; if (!node.Default.Value.IsKind(VBasic.SyntaxKind.NothingLiteralExpression)) { - optionalAttributes.Add(CS.SyntaxFactory.Attribute(ValidSyntaxFactory.IdentifierName("DefaultParameterValue"), arg)); + if (vbSymbol?.Type?.SpecialType == SpecialType.System_Decimal && defaultExpression is CSSyntax.LiteralExpressionSyntax literalExpr) { + var literalValue = literalExpr.Token.Value; + if (literalValue is decimal decimalVal) { + var isInteger = decimalVal == Math.Round(decimalVal); + var newLiteral = isInteger ? CommonConversions.Literal((int)decimalVal) : CommonConversions.Literal((double)decimalVal); + arg = CommonConversions.CreateAttributeArgumentList(CS.SyntaxFactory.AttributeArgument(newLiteral)); + } + } + + if (vbSymbol?.Type?.TypeKind == TypeKind.Struct && vbSymbol?.Type?.SpecialType == SpecialType.None) { + arg = null; + } + + if (arg != null) { + optionalAttributes.Add(CS.SyntaxFactory.Attribute(ValidSyntaxFactory.IdentifierName("DefaultParameterValue"), arg)); + } } attributes.Insert(0, CS.SyntaxFactory.AttributeList(CS.SyntaxFactory.SeparatedList(optionalAttributes))); diff --git a/Tests/CSharp/MemberTests/MemberTests.cs b/Tests/CSharp/MemberTests/MemberTests.cs index da604f2d..2492f460 100644 --- a/Tests/CSharp/MemberTests/MemberTests.cs +++ b/Tests/CSharp/MemberTests/MemberTests.cs @@ -1576,4 +1576,43 @@ private void OptionalByRefWithDefault([Optional][DefaultParameterValue(""a"")] r CS7036: There is no argument given that corresponds to the required parameter 'str1' of 'MissingByRefArgumentWithNoExplicitDefaultValue.ByRefNoDefault(ref string)' "); } -} \ No newline at end of file + [Fact] + public async Task OptionalByRefParameterAsync886() + { + await TestConversionVisualBasicToCSharpAsync(@"Class Issue886 + Private Shared Sub OptionalParams() + FunctionWithOptionalParams() + End Sub + + Private Shared Sub FunctionWithOptionalParams(Optional ByRef structParam As TestStruct = Nothing, Optional ByRef decimalParam As Decimal = 0) + structParam = New TestStruct + decimalParam = 0 + End Sub + + Friend Structure TestStruct + Friend A As Boolean + End Structure +End Class", @"using System.Runtime.InteropServices; + +internal partial class Issue886 +{ + private static void OptionalParams() + { + TestStruct argstructParam = default; + decimal argdecimalParam = 0m; + FunctionWithOptionalParams(structParam: ref argstructParam, decimalParam: ref argdecimalParam); + } + + private static void FunctionWithOptionalParams([Optional] ref TestStruct structParam, [Optional, DefaultParameterValue(0)] ref decimal decimalParam) + { + structParam = new TestStruct(); + decimalParam = 0m; + } + + internal partial struct TestStruct + { + internal bool A; + } +}"); + } +}