1

There is a legacy Visual Basic class library targetting .Net Standard 2.0 currently:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.VisualBasic" Version="10.3.0" />
  </ItemGroup>
</Project>

There is also a class inside

Public Class Class1
  Public Shared Function TryGetInteger(ByVal value As Object) As Integer
    Dim out As Integer

    If Integer.TryParse(value, out) Then
      Return out
    End If

    Return Integer.MinValue
  End Function

  Public Shared Function BooleanToInt(ByVal bValue As Object) As Integer
    If (bValue = DBNull.Value) Then
      Return 0
    ElseIf bValue = True Then
      Return 1
    Else
      Return 2
    End If
  End Function
End Class

At this point everything works fine.

But changing <TargetFramework>netstandard2.0</TargetFramework> to 2.1 breaks the build with the following error in the Class1.TryGetInteger function:

Requested operation is not available because the runtime library function 'Microsoft.VisualBasic.CompilerServices.Conversions.ChangeType' is not defined

How can this be fixed?

EDIT: Please disregard below idea:

The first idea comes from this closed github issue, that suggests adding <VBRuntime>Default</VBRuntime> to the project file, but this results in error:

could not find library 'Microsoft.VisualBasic.dll'

But it is already linked as a package... Any ideas?

EDIT: As mentioned is the comments, my take on the linked github issue is a bit misleading, so I guess I'm back to the beginning with the Requested operation is not available error.

Yuriy Ivaskevych
  • 956
  • 8
  • 18
  • 1
    Your github link discusses FW 4.7. Standard 2.1 is Core and does not map to the classic FW, [which Microsoft.VisualBasic.dll is](https://github.com/dotnet/runtime/issues/27767). – GSerg Oct 23 '20 at 12:57
  • @GSerg Yeah... Thanks for noticing that, please disregard that link then, I've edited the question. So basically I'm back to the starting point – Yuriy Ivaskevych Oct 23 '20 at 13:14
  • 1
    There's also https://stackoverflow.com/q/48897920/11683, which is not too helpful either. – GSerg Oct 23 '20 at 13:25

2 Answers2

2

Integer.TryParse() expects a String, but the input argument type is Object.

You can fix the issue like this:

Public Shared Function TryGetInteger(value As Object) As Integer
    Dim out As Integer
    If Integer.TryParse(value.ToString(), out) Then Return out

    Return Nothing 'Same as Integer.MinValue in this context
End Function

The extra ToString() call is the same thing the old framework was doing for you implicitly. Now you're aware of it.

But really I'd do this:

Public Shared Function TryGetInteger(value As String) As Integer
    Dim out As Integer
    If Integer.TryParse(value, out) Then Return out

    Return Nothing
End Function

Which will probably bring up a whole new set of compiler errors, but there will be value in going back and fixing them at those calling locations. Most of the errors can be fixed by adding .ToString() to the end of value when calling the function, and any that can't were almost certainly hiding bugs.

Similarly for the BooleanToInt() function, I'd use explicit types, and maybe overloading to get better results, like this:

Public Shared Function BooleanToInt(bValue As DBNull) As Integer
    Return 0 'If this overload was selected, we know we want 0
End Function
Public Shared Function BooleanToInt(bValue As Boolean) As Integer
    If bValue Then Return 1
    Return 2
End Function
Public Shared Function BooleanToInt(bValue As Object) As Integer
    Return 2
End Function

As a rule of thumb, anywhere you need to use the Object type directly is a magnet for bugs. It's a smell in the code and something to avoid.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
  • Hmm, that's actually a helpful insight. We might need to consider just ad-hoc fixing that by `.ToString()`. Unfortunatelly, there's no chance the whole library would be refactored including external callers. Or we'll just leave it on .Net Standard 2.0, this question was raised more out of curiosity) – Yuriy Ivaskevych Oct 23 '20 at 15:38
  • I guess, I'll mark your answer as accepted - I think it is more to the point, thanks! – Yuriy Ivaskevych Oct 23 '20 at 15:43
1

The class methods are relying on the implicit type conversions implemented by the VB compiler when Option Strict is set to Off.

The safest way to rewrite the code would be to use a de-compiler and implement the conversion operations used by the compiler. That could get quite involved.

If there is some sanity in the code that calls the the class methods, then a simple rewrite like the following can be done to avoid the usage of compiler's helper conversion methods.

Public Shared Function TryGetInteger(ByVal value As Object) As Integer
  Dim out As Integer

  If Integer.TryParse(value.ToString, out) Then
    Return out
  End If

  Return Integer.MinValue
End Function

Public Shared Function BooleanToInt(ByVal bValue As Object) As Integer
  If (bValue Is DBNull.Value) Then
    Return 0
  Else
    If TypeOf bValue Is Boolean Then
      Return If(DirectCast(bValue, Boolean), 1, 2)
    Else
      Throw New ArgumentException("type of bValue must be either DbNull or Boolean")
    End If
  End If
End Function
TnTinMn
  • 11,522
  • 3
  • 18
  • 39
  • Yeah, as I just replied to other answer, there's a hell lot of references all around the codebase, so we might either "plug" the ad-hoc solution in few places after more thorough analysis or leave stuff as is. Thanks! – Yuriy Ivaskevych Oct 23 '20 at 15:42