In Visual Basic 6.0, the Null keyword indicated that a field contained no valid data, and the IsNull function was used to test for Null. In addition, Visual Basic 6 supported Null propagation when Null was used in an expression, the result of the expression would also be Null. For a more thorough discussion of data types in Visual Basic please refer to the Data Type documentation.
In Visual Basic .NET, the Null keyword is still a reserved word, but it has no syntactical value, and the IsNull function is no longer supported.
C# also reserves the null keyword, but it is not to be confused with Null in Visual Basic 6. Visual Basic's Null keyword indicated missing or invalid data in data field, which is the purpose of DbNull in the .Net Framework. C#'s version of null is closer to Visual Basic 6's Nothing keyword.
Also, Null propagation is no longer supported in the .NET framework. When upgrading Visual Basic 6 applications avoid null propagation.
During upgrade, Null is converted to DBNull, and IsNull is converted to IsDBNull of which there are several variants: Visual Basic's IsDBNull function, the Convert.IsDBNull method, the DataTableReader.IsDBNull method, and the IDataRecord.IsDBNull method).
The behavior of DBNull is slightly different than that of Null. Null could be used in functions and assignments as a Variant data type, however DBNull is a class and thus cannot be used as a direct replacement for Visual Basic's Null, DBNull.Value however can be passed as a value type in methods or assignments.
Where Null was used with a Variant data type, the Variant is converted to Object during upgrade; in these cases, depending on context, it may be more appropriate to use the Nothing and the IsNothing function for VB.Net. For C# use the null keyword and compare with null with the equality operators (== and !=).
Private Sub NullPropagation() Dim result As Variant Dim resultText AsString Dim varRight AsVariant Dim varLeft AsVariant ' Regular use of Left, Mid, Right varRight = "Hello world" result = Mid(varRight, 7, 5) resultText = resultText & "Mid(" & ResultTxt(varRight) & ", 7, 5) = " & ResultTxt(result) & vbCrLf & vbCrLf ' Null propagation ' Trimming of numeric values using Left, Mid, Right varLeft = 20 varRight = 10913857 result = varLeft + Mid(varRight, 2, 5) resultText = resultText & ResultTxt(varLeft) & " + Mid(" & ResultTxt(varRight) & ",2 ,5) = " & ResultTxt(result) & vbCrLf varRight = Null result = varLeft + Mid(varRight, 2, 5) resultText = resultText & ResultTxt(varLeft) & " + Mid(" & ResultTxt(varRight) & ", 2, 5) = " & ResultTxt(result) & vbCrLf & vbCrLf ' Null propagation with + operator varLeft = Null varRight = 45298301 result = varLeft + Left(varRight, 5) resultText = resultText & ResultTxt(varLeft) & " + Left(" & ResultTxt(varRight) & ", 5) = " & ResultTxt(result) & vbCrLf varLeft = "18205023" result = varLeft + Left(varRight, 5) resultText = resultText & ResultTxt(varLeft) & " + Left(" & ResultTxt(varRight) & ", 5) = " & ResultTxt(result) & vbCrLf & vbCrLf ' Null propagation with & (Concatenation) operator result = varLeft & varRight resultText = resultText & ResultTxt(varLeft) & " & " & ResultTxt(varRight) & " = " & ResultTxt(result) & vbCrLf MsgBox (resultText) EndSub Private Function ResultTxt(var AsVariant) If IsNull(var) Then ResultTxt = "Null" Else If TypeName(var) = "Integer"Or TypeName(var) = "Double"Or TypeName(var) = "Long" Then ResultTxt = CStr(var) Else ResultTxt = """" & var & """" End If End Function
Private Sub NullPropagation() Dim resultText AsString = "" Dim varLeft AsString = CStr(20) ' Regular use of Left, Mid, Right Dim varRight AsString = "Hello world" Dim result AsString = varRight.Substring(6, Math.Min(varRight.Length, 5)) resultText = resultText & "Mid(" & ResultTxt(varRight) & ", 7, 5) = " & ResultTxt(result) & Strings.Chr(13) & Strings.Chr(10) & Strings.Chr(13) & Strings.Chr(10) ' Null propagation ' Trimming of numeric values using Left, Mid, Right varRight = CStr(10913857) result = varLeft & varRight.Substring(1, Math.Min(varRight.Length, 5)) resultText = resultText & ResultTxt(varLeft) & " + Mid(" & ResultTxt(varRight) & ",2 ,5) = " & ResultTxt(result) & Strings.Chr(13) & Strings.Chr(10) 'UPGRADE_WARNING: (1049) Use of Null/IsNull() detected. varRight = DBNull.Value result = varLeft & varRight.Substring(1, Math.Min(varRight.Length, 5)) resultText = resultText & ResultTxt(varLeft) & " + Mid(" & ResultTxt(varRight) & ", 2, 5) = " & ResultTxt(result) & Strings.Chr(13) & Strings.Chr(10) & Strings.Chr(13) & Strings.Chr(10) ' Null propagation with + operator 'UPGRADE_WARNING: (1049) Use of Null/IsNull() detected. varLeft = DBNull.Value result = varLeft & varRight.Substring(0, Math.Min(varRight.Length, 5)) resultText = resultText & ResultTxt(varLeft) & " + Left(" & ResultTxt(varRight) & ", 5) = " & ResultTxt(result) & Strings.Chr(13) & Strings.Chr(10) varLeft = "18205023" result = varLeft & varRight.Substring(0, Math.Min(varRight.Length, 5)) resultText = resultText & ResultTxt(varLeft) & " + Left(" & ResultTxt(varRight) & ", 5) = " & ResultTxt(result) & Strings.Chr(13) & Strings.Chr(10) & Strings.Chr(13) & Strings.Chr(10) 'Following statement will throw an error Left$ will not take Null 'result = varLeft + Left$(varRight, 5) ' Null propagation with & (Concatenation) operator result = varLeft & varRight resultText = resultText & ResultTxt(varLeft) & " & " & ResultTxt(varRight) & " = " & ResultTxt(result) & Strings.Chr(13) & Strings.Chr(10) MessageBox.Show(resultText, Application.ProductName) EndSub PrivateFunction ResultTxt(ByRef varRight AsString) AsString 'UPGRADE_WARNING: (1049) Use of Null/IsNull() detected. 'UPGRADE_WARNING: (1041) TypeName has a new behavior. If Convert.IsDBNull(varRight) Then Return"Null" Else If varRight.GetType().Name = "Integer"Or varRight.GetType().Name = "Double"Or varRight.GetType().Name = "Long"Then Return varRight Else Return"""" & varRight & """" End If End Function
Code that uses Null propagation requires considerable work in either the migrated version or the original VB6 code to remove such propagation.
One approach if the affected code is small is to preface it with an If statement checking for DBNull values, as done in the sample code. Another approach if using a typed DataSet is to take advantage of the built-in IsFieldNameNull() methods to determine if a particular field is set to DBNull.Value. Alternatively, one may use the IsNull() method for DataRows to test if a particular field is DBNull.
Another approach is to create a function that wraps this logic. That's the approach taken with the ResultTxt function which handles the output of DBNulls for us (as well as the display of strings with quotes around them).
In this example, the input sample was limited and given C# strong-type nature we're forced to contemplate many more scenarios in code than with Visual Basic.Net's more dynamic typing. In the solution for this sample reduced the input types to System.Int32 to keep code brief.
Additionally, two methods were created VbLeft and VbMid to replicate the behavior of the original VB functions. The reason for doing this is because the String.Substring is much more stringent about the parameters it takes and bound checks them, throwing an exception if any of them are out of bounds. Visual Basic 6 automatically handled these out of range cases.
C#'s behavior is helpful though in highlighting possible problem areas. So another solution might involve dynamically changing the trim size based on the input. In this case C#'s strongly-type system require we pay more attention to the intent of the code and fix it accordingly.
private string VbMid(string value, int start, int length) { length = (length > value.Length) value.Length - (start - 1) : length; if(value.Length > start) { return value.Substring(start - 1, length); } return string.Empty; } private string VbLeft(object value, int length) { if (value == null || DBNull.Value.Equals(value)) { return string.Empty; } else { string temp = value.ToString(); if (temp.Length > length) { return temp.Substring(0, length); } else return temp; } } private void NullPropagation() { string resultText = String.Empty; // Regular use of Left, Mid, Right object varRight = "Hello world"; object result = VbMid(varRight.ToString(), 7, 5); resultText = resultText + "Mid(" + ResultTxt(varRight) + ", 7, 5) = " + ResultTxt(result) + "\r\n" + "\r\n"; // Null propagation // Trimming of numeric values using Left, Mid, Right object varLeft = 20; varRight = 10913857; result = (int)varLeft + Convert.ToInt32(VbMid(varRight.ToString(), 2, 5)); resultText = resultText + ResultTxt(varLeft) + " + Mid(" + ResultTxt(varRight) + ",2 ,5) = " + ResultTxt(result) + "\r\n"; //UPGRADE_WARNING: (1049) Use of Null/IsNull() detected. varRight = DBNull.Value; int intLeft = (varLeft isint) (int)varLeft : 0; // Check for DBNull object tempRight = (DBNull.Value.Equals(varRight)) 0 : varRight; int intRight = (tempRight isint) (int)tempRight : 0; result = intLeft + intRight; resultText = resultText + ResultTxt(varLeft) + " + Mid(" + ResultTxt(varRight) + ", 2, 5) = " + ResultTxt(result) + "\r\n" + "\r\n"; // Null propagation with + operator //UPGRADE_WARNING: (1049) Use of Null/IsNull() detected. varLeft = DBNull.Value; varRight = "45298301"; result = varLeft + VbLeft(varRight, 5);//.Substring(0, Math.Min(varRight.Length, 5)); resultText = resultText + ResultTxt(varLeft) + " + Left(" + ResultTxt(varRight) + ", 5) = " + ResultTxt(result) + "\r\n"; varLeft = "18205023"; result = varLeft + VbLeft(varRight, 5);//.Substring(0, Math.Min(varRight.Length, 5)); resultText = resultText + ResultTxt(varLeft) + " + Left(" + ResultTxt(varRight) + ", 5) = " + ResultTxt(result) + "\r\n" + "\r\n"; // Null propagation with & (Concatenation) operator result = varLeft.ToString() + varRight.ToString(); resultText = resultText + ResultTxt(varLeft) + " & " + ResultTxt(varRight) + " = " + ResultTxt(result) + "\r\n"; MessageBox.Show(resultText, Application.ProductName); } private string ResultTxt(object var) { //UPGRADE_WARNING: (1049) Use of Null/IsNull() detected. //UPGRADE_WARNING: (1041) TypeName has a new behavior. if (Convert.IsDBNull(var)) { return"Null"; } else if (var is int || var is double || var is long) { return var.ToString(); } else { return"\"" + var + "\""; } }
8834 N Capital of Texas Hwy, Ste 302
Austin, TX 78759
Call us: +1.512.243.5754
info@wearegap.com