I need to convert a bunch of VB.NET code to C#. Instant C# is a great helper but one area... string case-insensitive VB.NET code.
Ahead of conversion, I would like to find a way to search for the VB.NET code that does string equals evaluations and change them to use String.Compare(x,y,StringComparison.CurrentCultureIgnoreCase)=0.
Is there a way in Visual Studio 2017 to find these string evaluations? Maybe leveraging .NET Compiler Platform SDK?
For example Test routine would be changed like representative of Test2 routine then converted to C#.
Option Compare Text
.
.
.
Private Sub Test()
Dim x as string = "x"
Dim y as string = "y"
If x = y then msgbox("They match")
End Sub
Private Sub Test2()
Dim x as string = "x"
Dim y as string = "y"
If String.Compare(x, y, StringComparison.CurrentCultureIgnoreCase) = 0 then msgbox("They match")
End Sub
C# converted output below
private static void Test()
{
string x = "x";
string y = "y";
if ((x ?? string.Empty) == (y ?? string.Empty))
{
MessageBox.Show("They match");
}
}
private static void Test2()
{
string x = "x";
string y = "y";
if (string.Compare(x, y, StringComparison.CurrentCultureIgnoreCase) == 0)
{
MessageBox.Show("They match");
}
}
While the original question has not been answered, the NEED to answer it has been rendered moot given that the latest Instant C# creates case insensitive output. Below is the output of Test routine.
private static void Test()
{
string x = "x";
string y = "y";
if (string.Equals(x ?? string.Empty, y ?? string.Empty, StringComparison.OrdinalIgnoreCase))
{
MessageBox.Show("They match");
}
}
Related
I have this conversion in my Kotlin class for Android:
val binary = "01000100000111001011011011100010111000110011010111010110"
val hexadecimal = BigInteger(binary, 2).toString(16)
Which is producing the expected value of 441CB6E2E335D6.
Now I want to reproduce this in Visual Basic and I am doing something like this:
Dim binary = "01000100000111001011011011100010111000110011010111010110"
Dim hexadecimal = BigInteger.Parse(binary, 2).ToString("X")
Which is producing 0A7108304A751AFEC876F740BC1F2CB59772FB7C6C753E.
I am not an expert in Visual Basic, but from what I researched, I think this is the right way to convert a binary to hexadecimal. What I am doing wrong?
You can write a simple parser for the string representing the bits:
Dim sb As StringBuilder = New StringBuilder()
For pos As Integer = 0 To binary.Length - 8 Step 8
sb.Append(Convert.ToByte(binary.Substring(pos, 8), 2).ToString("X2"))
Next
Console.WriteLine(sb) will print "441CB6E2E335D6"
Or use a Module to add an extension method to the string data type:
Imports System.Runtime.CompilerServices
Imports System.Text
Module modStringExtensions
<Extension()>
Public Function ToHexFromBits(ByVal Value As String) As String
If (Not (Value.Length Mod 8 = 0)) Then Throw New FormatException("Invalid string length")
Dim sb As StringBuilder = New StringBuilder()
For pos As Integer = 0 To Value.Length - 8 Step 8
sb.Append(Convert.ToByte(Value.Substring(pos, 8), 2).ToString("X2"))
Next
Return sb.ToString()
End Function
End Module
Then use the extension to convert the bits string to a HEX representation:
Dim result As String = binary.ToHexFromBits()
Following code is c#, but might not be too hard to translate it to vb.net.
string BinToHex(string value)
{
var res = new char[(int)(value.Length / 4)];
int j = res.Length-1;
for (int i = value.Length - 1; i > 0; i -= 4)
{
int x = ((int)value[i]-48)
+((int)value[i-1]-48)*2
+((int)value[i-2]-48)*4
+((int)value[i-3]-48)*8;
res[j--] = x.ToString("X")[0];
}
return new string(res);
}
Beware: it won't handle input that has not the proper number of bits (multiple of 4). Anyway, the idea is that you can translate between base 2 and base 16 without the use of base 10. You could even step from left to right.
Assuming the following...
Dim x as string = "hello"
dim y as string = "world"
dim z as string = "{x} {y}" 'Note: no $ (not interpolation )
I would like to call a method that when passing z would return "hello world"
Note: z can have 0 or more {} and should be evaluated based on the scope of the caller
Is this possible?
String interpolation is available in VB.NET 14. To interpolate a string, do the following...
Dim x as string = "hello"
Dim y as string = "world"
Dim z = $"{x} {y}"
This is shorthand for...
dim z = String.Format({0}{1}, x,y)
For more information on VB.NET 14, see 14 Top Improvements in Visual Basic 14
It is, by using String.Format, if you use numbers instead of letters in your placeholders:
Dim x As String = "hello"
Dim y As String = "world"
Dim z As String = "{0} {1}"
Dim output As String = String.Format(z, x, y)
Since any string can be passed to String.Format as the format string, even if it's dynamic, and since the rest of the parameters are a param array, you could even do something like this (though it's a needless wrapper around the already usable method):
Public Function MyFormat(format As String, values() As Object) As String
Return String.Format(format, values)
End Function
Something like SmartFormat.NET, with named placeholders may be what you are looking for. You would need to pass in all possible context variables - I don't know of any way to capture the current scope.
Dim x As String = "hello"
Dim y As String = "world"
Dim notUsed As String = "Don't care"
Dim z As String = "{x} {y}"
Dim output As String = Smart.Format(z, New With { x, y, notUsed })
Console.WriteLine(output)
hello world
I have such entries in Winforms ComboBox:
Font 8 pt
Font 9 pt
Font 10 pt
Font 12 pt
Font 14 pt
Then I have search string " 9 ".
Is here native way to find index by search string without looping?
I try this:
Dim a As Integer = myComboBox.FindString(" 9 ", 0)
... but without good result.
First, no, there is no available method in the framework that searches for sub-string in combobox items and returns the index of the first item which contains the search parameter.
But even ComboBox.FindString uses a loop as you can see in the source.
So there is nothing bad in using one, you could write an extension method for this:
public static class ControlExtensions
{
public static int FindSubStringIndex(this ComboBox combo, string subString, StringComparison comparer = StringComparison.CurrentCulture)
{
// Sanity check parameters
if(combo == null) throw new ArgumentNullException("combo");
if (subString == null) {
return -1;
}
for (int index = 0; index < combo.Items.Count; index++)
{
object obj = combo.Items[index];
if(obj == null) continue;
string item = Convert.ToString(obj, CultureInfo.CurrentCulture);
if (string.IsNullOrWhiteSpace(item) && string.IsNullOrWhiteSpace(subString))
return index;
int indexInItem = item.IndexOf(subString, comparer);
if (indexInItem >= 0)
return index;
}
return -1;
}
}
Now you can use it in this way:
int index = combo.FindSubStringIndex("9");
Whoops, VB.NET:
Public Module ControlExtensions
<System.Runtime.CompilerServices.Extension> _
Public Function FindSubStringIndex(combo As ComboBox, subString As String, Optional comparer As StringComparison = StringComparison.CurrentCulture) As Integer
' Sanity check parameters
If combo Is Nothing Then
Throw New ArgumentNullException("combo")
End If
If subString Is Nothing Then
Return -1
End If
For index As Integer = 0 To combo.Items.Count - 1
Dim obj As Object = combo.Items(index)
If obj Is Nothing Then
Continue For
End If
Dim item As String = Convert.ToString(obj, CultureInfo.CurrentCulture)
If String.IsNullOrWhiteSpace(item) AndAlso String.IsNullOrWhiteSpace(subString) Then
Return index
End If
Dim indexInItem As Integer = item.IndexOf(subString, comparer)
If indexInItem >= 0 Then
Return index
End If
Next
Return -1
End Function
End Module
I have a Tlist that contains addresses. When I sort the list, numbers in the address are considered a string, and it doesn't sort correctly. How should I sort the list ascending?
Dim sortme As List(Of data) = tempdata 'main list containing addresses as strings.
sortme.Sort(Function(p1 As data, p2 As data) numorder(p1.Value).CompareTo(numorder(p2.Value)))
Private Function numorder(ByVal str As String)
Try
Dim words() As String = str.Split(" "c) 'read string up to first space (for number)
Return Convert.ToInt32(words(0))
Catch ex As Exception
End Try
End Function
Example of current output:
1001 street name
103 street name
1021 street name
It should be:
103 street name
1001 street name
1021 street name
The idea is to write your own comparer which will firs consider the number prefix and then the string itself. This comparer can be then used anywhere, for instance in LINQ OrderBy(). Here an example in c# see full VB.NET version below.
public class StreetComparer : IComparer<string>
{
public int Compare(string x, string y)
{
int indexOfSpaceX = x.IndexOf(' ');
string numericalPartX = x.Substring(0, indexOfSpaceX);
int indexOfSpaceY = y.IndexOf(' ');
string numericalPartY = y.Substring(0, indexOfSpaceY);
int numberX;
int numberY;
if(!int.TryParse(numericalPartX, out numberX) ||
!int.TryParse(numericalPartY, out numberY))
{
//Some code to handle the case where number is missing
throw new ArgumentException();
}
if (numberX!=numberY)
{
return numberX-numberY;
}
string textPartX = x.Substring(indexOfSpaceX + 1);
string textPartY = x.Substring(indexOfSpaceY + 1);
return String.Compare(textPartX, textPartY, true, CultureInfo.CurrentCulture);
}
}
class Program
{
static void Main(string[] args)
{
var myStreets = new[] {"01 aaa", "02 bbb"};
var result = myStreets.OrderBy(s => s, new StreetComparer());
}
}
Now a VB.NET version adapted exactly to your use case a List with classes sorted by property:
Public Class StreetComparer
Implements IComparer(Of String)
Public Function Compare(x As String, y As String) As Integer
Dim indexOfSpaceX As Integer = x.IndexOf(" "C)
Dim numericalPartX As String = x.Substring(0, indexOfSpaceX)
Dim indexOfSpaceY As Integer = y.IndexOf(" "C)
Dim numericalPartY As String = y.Substring(0, indexOfSpaceY)
Dim numberX As Integer
Dim numberY As Integer
If Not Integer.TryParse(numericalPartX, numberX) OrElse Not Integer.TryParse(numericalPartY, numberY) Then
'Some code to handle the case where number is missing
Throw New ArgumentException()
End If
If numberX <> numberY Then
Return numberX - numberY
End If
Dim textPartX As String = x.Substring(indexOfSpaceX + 1)
Dim textPartY As String = x.Substring(indexOfSpaceY + 1)
Return [String].Compare(textPartX, textPartY, True, CultureInfo.CurrentCulture)
End Function
End Class
Public Class Person
Public Property Value() As String
Get
Return m_Value
End Get
Set
m_Value = Value
End Set
End Property
Private m_Value As String
Public Sub New(value__1 As String)
Value = value__1
End Sub
End Class
Class Program
Private Shared Sub Main(args As String())
Dim sortme As New List(Of Person)(New () {New Person("1001 street name"), New Person("103 street name"), New Person("1021 street name")})
Dim result = sortme.OrderBy(Function(p) p.Value, New StreetComparer())
For Each person As var In result
Console.WriteLine(person.Value)
Next
Console.ReadKey()
End Sub
End Class
I was watching a screencast of someone using Resharper (on VS 2010 or 2008, not sure) where they were able to fill in a test name with a string literal:
public class FooTest
{
public void "runs backgrounnd process until complete"
and then some command transformed it to
public class FooTest
{
public void runs_backgrounnd_process_until_complete()
{
I was wondering if anyone knew what that command was.
It is a visual studio macro that originally came from JP Boodhoo's Nothing But .NET Boot Camp class. This is it:
Sub ConvertLine()
If DTE.ActiveDocument Is Nothing Then Return
Dim isOpen As Boolean = OpenUndo("ConvertLine")
Dim selection As TextSelection = CType(DTE.ActiveDocument.Selection(), EnvDTE.TextSelection)
selection.SelectLine()
If selection.Text = "" Then Return
Dim classKeyword As String = "class """
Dim methodKeyword As String = "void """
Dim classIndex As Integer = selection.Text.IndexOf(classKeyword)
Dim methodIndex As Integer = selection.Text.IndexOf(methodKeyword)
If classIndex + methodIndex < 0 Then Return
Dim index = CType(IIf(classIndex >= 0, classIndex, methodIndex), Integer)
Dim prefix = selection.Text.Substring(0, index) + CType(IIf(classIndex >= 0, classKeyword, methodKeyword), String)
Dim description As String = selection.Text.Replace(prefix, String.Empty)
Dim conversion As String = Common.ReplaceSpacesWithUnderscores(description)
conversion = Common.ReplaceApostrophesWithUnderscores(conversion)
conversion = Common.ReplaceQuotesWithUnderscores(conversion)
selection.Text = prefix.Replace("""", String.Empty) + conversion
If prefix.Contains(methodKeyword) Then selection.LineDown() Else selection.LineUp()
selection.EndOfLine()
CloseUndo(isOpen)
End Sub
Looks like a "live template". If you notice, he types in fact, which is then replaced by the test method's skeleton. Edit, looks like it comes from the xUnit.net contrib project. You should be able to do something similar for an nUnit test case as well.