How to I fix my deserialize error? - vb.net

Why, hello everyone!
I've got this program i've been working on for months. Basic back story of it is, its supposed to be able to transport and install applications for windows in the background, like iCloud does for apps!
Anywho, i'm using a serialize/deserialize method to save the properties (eg admin username and passwordhash, directories, ports, etc.).
I have a class called 'PropertyNest' representing the properties and links to memory allocations. I'll cut it down to only the parts that the XMLSerializer looks at and saves.
Public Class PropertyNest
'Huge bunch of functions that we dont need to look at
'#######################
Public _wasLoadedFromFile As Boolean = False
Private _port As Integer = 201
Private _httpPort As Integer = 202
Private _rootFolder As String = "\appstreamRoot"
Private _adminUser As String = "Admin"
Private _adminPass As String = "21232F297A57A5A743894A0E4A801FC3" 'admin
Private _appstreamServerType As appStreamServerType = appStreamServerType.http
Private _useDES3forserver As Boolean = True
Private _encDES3pswd As String = "21232F297A57A5A743894A0E4A801FC3" 'admin
'Properties and descriptors for 'PropertyGrid' object go here \|/
'=================================================================
End Class
And its declared in the main window, serverMain like this,
Public Shared Property_Nest As AdvancedSettings.PropertyNest
and initialized later in like this,
If settingsfilename = "" Then
Property_Nest = New AdvancedSettings.PropertyNest()
Else
If propFileEncrypted = False Then
WriteLog("From unprotected file...", False)
Try
Property_Nest = AdvancedSettings.PropertyNest.LoadFrom(settingsfilename)
Catch ex As Exception
WriteLog("FAILED! Making default property nest...")
Property_Nest = New AdvancedSettings.PropertyNest()
End Try
Else
WriteLog("From encrypted file...", False)
Try
Property_Nest = AdvancedSettings.PropertyNest.LoadFrom(settingsfilename, True, propFilePswd)
Catch ex As Exception
WriteLog("FAILED! Making default property nest...", False)
Property_Nest = New AdvancedSettings.PropertyNest()
End Try
End If
End If
Thats all well and good. Loading it from the file that its saved to is the problem. Inside the PropertyNest class, I have 2 serializers programmed like so:
(Sorry its a bunch, there's optional encrypting of the serialized products with TrippleDES)
Public Sub SaveAs(ByVal filename As String, Optional ByVal Encrypted As Boolean = False)
Dim extra As String
If Encrypted = True Then : extra = "Encrypted? : Yes." : Else : extra = "Encrypted? : No."
End If
If filename = Nothing Then
Exit Sub
End If
writeLog2("Saving Property Nest to: " & filename & vbCrLf & extra, False)
If Encrypted = False Then
Dim writer As New Xml.Serialization.XmlSerializer(GetType(PropertyNest))
Dim file As New System.IO.StreamWriter(filename)
writer.Serialize(file, Me)
file.Close()
Else
Dim writer As New Xml.Serialization.XmlSerializer(GetType(PropertyNest))
Dim memstream As New System.IO.MemoryStream
writer.Serialize(memstream, Me)
memstream.Seek(0, IO.SeekOrigin.Begin)
Dim file As New System.IO.StreamWriter(filename)
Dim memstreamReader As New System.IO.StreamReader(memstream)
Do
file.WriteLine(serverMain.admin_des3Manager.Encrypt(memstreamReader.ReadLine()))
Loop Until memstreamReader.EndOfStream = True
file.Close()
End If
writeLog2("OK!")
End Sub
Shared Function LoadFrom(ByVal filename As String, Optional ByVal EncryptedWithPswd As Boolean = False, Optional ByVal Password As String = "") As PropertyNest
Dim reader As New Xml.Serialization.XmlSerializer(GetType(PropertyNest))
Dim file As New System.IO.StreamReader(filename)
Dim newPropNest As PropertyNest
If EncryptedWithPswd = False Then
newPropNest = reader.Deserialize(file) 'Error in XML Document(11, 3)
Else
If Password = "" Then
Dim convertedStream As New System.IO.MemoryStream
Dim convertedWriter As New System.IO.StreamWriter(convertedStream)
Do
convertedWriter.WriteLine(serverMain.admin_des3Manager.Decrypt(file.ReadLine()))
Loop Until file.EndOfStream = True
convertedWriter.Close()
newPropNest = reader.Deserialize(convertedStream)
Else
Dim tempDES3 As New DES3(Password)
Dim convertedStream As New System.IO.MemoryStream
Dim convertedWriter As New System.IO.StreamWriter(convertedStream)
Do
convertedWriter.WriteLine(tempDES3.Decrypt(file.ReadLine()))
Loop Until file.EndOfStream = True
convertedWriter.Close()
newPropNest = reader.Deserialize(convertedStream)
End If
End If
Return newPropNest
End Function
I marked the error in there.
Phew. Almost done.
i'm only worried about unencrypted right now, so i did my duty to save a custom, non default property nest, and it wrote to the file like so:
<?xml version="1.0" encoding="utf-8"?>
<PropertyNest xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<_wasLoadedFromFile>false</_wasLoadedFromFile>
<ServerPort>2010</ServerPort>
<AdminUser>Matthew</AdminUser>
<AdminPasswordHash>21232F297A57A5A743894A0E4A801FC3</AdminPasswordHash>
<AppStreamPort>2020</AppStreamPort>
<AppStream_ServerRoot>\appstreamRoot</AppStream_ServerRoot>
<UseDES3>true</UseDES3>
<EncDES3Pswd>21232F297A57A5A743894A0E4A801FC3</EncDES3Pswd>
</PropertyNest>
Awesome! now.... If you look at the 'LoadFrom' function, you'll see i commented the line where i get the error... I dont see an error at 11, 3. Please help!
Thanks so much :D

Your XML is valid, however the class you need to deserialise, should be like this according to visual studio, copy you XML to the clipboard, go to the edit menu, paste special and past XML as classes give you this, give it a try see if it works, you can use a c# to vb converter to change to VB if you need to.
/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class PropertyNest
{
private bool _wasLoadedFromFileField;
private ushort serverPortField;
private string adminUserField;
private string adminPasswordHashField;
private ushort appStreamPortField;
private string appStream_ServerRootField;
private bool useDES3Field;
private string encDES3PswdField;
/// <remarks/>
public bool _wasLoadedFromFile
{
get
{
return this._wasLoadedFromFileField;
}
set
{
this._wasLoadedFromFileField = value;
}
}
/// <remarks/>
public ushort ServerPort
{
get
{
return this.serverPortField;
}
set
{
this.serverPortField = value;
}
}
/// <remarks/>
public string AdminUser
{
get
{
return this.adminUserField;
}
set
{
this.adminUserField = value;
}
}
/// <remarks/>
public string AdminPasswordHash
{
get
{
return this.adminPasswordHashField;
}
set
{
this.adminPasswordHashField = value;
}
}
/// <remarks/>
public ushort AppStreamPort
{
get
{
return this.appStreamPortField;
}
set
{
this.appStreamPortField = value;
}
}
/// <remarks/>
public string AppStream_ServerRoot
{
get
{
return this.appStream_ServerRootField;
}
set
{
this.appStream_ServerRootField = value;
}
}
/// <remarks/>
public bool UseDES3
{
get
{
return this.useDES3Field;
}
set
{
this.useDES3Field = value;
}
}
/// <remarks/>
public string EncDES3Pswd
{
get
{
return this.encDES3PswdField;
}
set
{
this.encDES3PswdField = value;
}
}
}

Related

Error 'Value cannot be null:nodeName' when creating new iteration

I'm getting an error when attempting to create a new Iteration using the Client SDK:
Value cannot be null.
Parameter name: nodeName
As a test, I tried creating it using Postman and the REST API—as suggested here—and it succeeded.
I've been using this successfully for quite a while now to stub out my sprint hierarchy for the year. This is the first such occurrence of this error—past year runs have gone off without a hitch. I haven't changed anything (that I know of) since last year's successful run.
As we can see, the iteration's Name property is being properly set. I tried Overloads instead of Shadows, but that didn't help.
How can I troubleshoot this to find out what nodeName is and how to populate it using the Client SDK?
Here's my code:
Module Main()
Private Sub AddYear(Year As Integer, Client As WorkItemTrackingHttpClient)
Dim oIterationYear As Classifications.Iteration
Dim dFinishDate As Date
Dim dStartDate As Date
Console.WriteLine($"Year:{vbTab}{vbTab}{Year}")
dFinishDate = New Date(Year, 12, 31)
dStartDate = New Date(Year, 1, 1)
oIterationYear = New Classifications.Iteration(Client, TeamProject, Year, dStartDate, dFinishDate)
oIterationYear.Save()
...
End Sub
End Module
Public Class Iteration
Inherits Base
Public Sub New(Client As WorkItemTrackingHttpClient, TeamProject As TeamProjects, Name As String, StartDate As Date, FinishDate As Date)
Me.New(Client, TeamProject, Name, StartDate, FinishDate, Nothing)
End Sub
Public Sub New(Client As WorkItemTrackingHttpClient, TeamProject As TeamProjects, Name As String, StartDate As Date, FinishDate As Date, Parent As Iteration)
MyBase.New(Client, TeamProject, Parent)
Me.StructureType = TreeNodeStructureType.Iteration
Me.FinishDate = FinishDate
Me.StartDate = StartDate
Me.Name = Name
End Sub
...
End Class
Public MustInherit Class Base
Inherits WorkItemClassificationNode
Public Sub New(Client As WorkItemTrackingHttpClient, TeamProject As TeamProjects, Parent As Base)
Me.ProjectName = TeamProject.ToDescription
Me.Parent = Parent
Me.Client = Client
End Sub
Public Sub Save()
If Me.Parent.IsNothing Then
Me.Node = Me.Client.CreateOrUpdateClassificationNodeAsync(Me, Me.ProjectName, Me.StructureType).Result <-- Error
Else
Me.Node = Me.Client.CreateOrUpdateClassificationNodeAsync(Me, Me.ProjectName, Me.StructureType, path:=Me.Path).Result
End If
End Sub
...
Public Shadows Property Name As String
Get
If Me.Node.IsNothing Then
Name = Me._Name
Else
Name = Me.Node.Name
End If
End Get
Set(Value As String)
Me._Name = Value
End Set
End Property
Private _Name As String
End Class
Note: this is a language-agnostic question, thus I've intentionally omitted the VB.NET tag. An answer can come in either VB.NET or C#—I'm fine with either one.
-- EDIT --
Based on the design suggestions found in the accepted answer, I've come up with this solution that works:
Public MustInherit Class Base
Public Sub New(Client As WorkItemTrackingHttpClient, TeamProject As TeamProjects, Parent As Base)
Me.Node = New WorkItemClassificationNode With {
.StructureType = StructureType,
.Name = Name
}
Me.ProjectName = TeamProject.ToDescription
Me.Parent = Parent
Me.Client = Client
Me.Name = Name
End Sub
Public Sub Save()
If Me.Parent.IsNothing Then
Me.Node = Me.Client.CreateOrUpdateClassificationNodeAsync(Me.Node, Me.ProjectName, Me.StructureType).Result
Else
Me.Node = Me.Client.CreateOrUpdateClassificationNodeAsync(Me.Node, Me.ProjectName, Me.StructureType, path:=Me.Path).Result
End If
End Sub
...
Public Property Name As String
Get
Return Me.Node.Name
End Get
Private Set(Value As String)
Me.Node.Name = Value
End Set
End Property
End Class
Essentially all I did was remove the base class' inheritance from WorkItemClassificationNode and store a node reference internally in all cases. I also simplified the Name property implementation.
As for why it suddenly stopped working with no change in my code, the only thing I can think of is the remote possibility that there was a change in the compiler that affected how the SDK evaluates the Shadows and Overloads keywords. That's a long shot, I know, but I'm at a complete loss otherwise.
Bottom line, it works now.
I can create new iteration using Microsoft.TeamFoundation.WorkItemTracking.WebApi in Azure DevOps Services .NET SDK.
Please check out below example:
class Program
{
static void Main(string[] args)
{
Uri accountUri = new Uri("https://dev.azure.com/org/");
string personalAccessToken = "pat";
VssConnection _connection = new VssConnection(accountUri, new VssBasicCredential(string.Empty, personalAccessToken));
WorkItemTrackingHttpClient workItemTrackingHttpClient = _connection.GetClient<WorkItemTrackingHttpClient>();
Iteration iteration = new Iteration(workItemTrackingHttpClient,2021, "projectName");
iteration.SaveNode();
}
}
public class Iteration
{
WorkItemTrackingHttpClient client;
WorkItemClassificationNode node;
string project;
string path;
public Iteration(WorkItemTrackingHttpClient client, int Year, string project, string path=null) {
this.client = client;
node = new WorkItemClassificationNode();
this.project = project;
this.path = path;
IDictionary<string, object> DateAttr = new Dictionary<string, object>();
DateAttr.Add("startDate", new DateTime(Year, 1, 1));
DateAttr.Add("finishDate", new DateTime(Year, 12, 31));
node.Attributes = DateAttr;
node.Name = Year.ToString();
node.StructureType = TreeNodeStructureType.Iteration;
}
public void SaveNode()
{
var res = client.CreateOrUpdateClassificationNodeAsync(node, project, TreeStructureGroup.Iterations, path).Result;
Console.WriteLine(res.Id);
}
}
See below result:
I can reproduce above error Value cannot be null. Parameter name: nodeName. If i intentionally didnot set the node.Name = null; You can debug your code to check why the node name was not set.

VB.NET: Instantiate a nested property by reflection

I want to set the values of the properties via reflection. In this thread they propose a solution. But the problem with the solution is that it is not instantiating the properties. But I want to check and instantiate the properties if necessary. My DTO is:
Public Class root
Public Property Printing() As rootPrinting
End Class
Public Class rootPrinting
Public Property Printer() As String
Public Property PrinterBatch() As String
End Class
Now for setting the properties I have defined the following function:
Public Sub SetProperty(ByVal target As Object, ByVal compoundProperty As String, ByVal value As Object)
Dim properties As String() = compoundProperty.Split("."c)
For i As Integer = 0 To properties.Length - 1 - 1
Dim propertyToGet As PropertyInfo = target.[GetType]().GetProperty(properties(i))
target = propertyToGet.GetValue(target, Nothing)
if IsNothing(target) then
if propertyToGet.PropertyType.IsClass then
target = Activator.CreateInstance(propertyToGet.PropertyType)
End If
End If
Next
Dim propertyToSet As PropertyInfo = target.[GetType]().GetProperty(properties.Last())
propertyToSet.SetValue(target, value, Nothing)
End Sub
Then I call it like this:
Dim configObject as New root
SetProperty(configObject , "Printing.Printer","skjfkd")
If before calling SetProperty(configObject,...) I instantiate configObject.Printing then it will work fine:
Dim configObject as New root
configObject.Printing = new rootPrinting()
SetProperty(configObject , "Printing.Printer","skjfkd")
Otherwise after calling SetProperty(...), configObject.Printing will be Nothing.
It seems that when calling Activator.CreateInstance(propertyToGet.PropertyType) the reference to the original object is lost. While the object in the function is really initialized, the main object remains Nothing. How can I instantiate the class property correctly?
This question/answer was very helpful to me (thanks Code Pope!), I needed the same code in C#:
public void SetProperty(object target, string compoundProperty, object value)
{
var properties = compoundProperty.Split('.');
for (int i=0; i < (properties.Length - 1); i++)
{
var propertyToGet = target.GetType().GetProperty(properties[i]);
var property_value = propertyToGet.GetValue(target, null);
if (property_value == null)
{
if (propertyToGet.PropertyType.IsClass)
{
property_value = Activator.CreateInstance(propertyToGet.PropertyType);
propertyToGet.SetValue(target, property_value);
}
}
target = property_value;
}
var propertyToSet = target.GetType().GetProperty(properties.Last());
propertyToSet.SetValue(target, value);
}
Ok. The problem was solved. To solve the problem the code has to be modified as following:
Public Sub SetProperty(ByVal target As Object, ByVal compoundProperty As String, ByVal value As Object)
Dim properties As String() = compoundProperty.Split("."c)
For i As Integer = 0 To properties.Length - 1 - 1
Dim propertyToGet As PropertyInfo = target.GetType().GetProperty(properties(i))
Dim property_value = propertyToGet.GetValue(target, Nothing)
If IsNothing(property_value) Then
If propertyToGet.PropertyType.IsClass Then
property_value = Activator.CreateInstance(propertyToGet.PropertyType)
propertyToGet.SetValue(target, property_value)
End If
End If
target = property_value
Next
Dim propertyToSet As PropertyInfo = target.GetType().GetProperty(properties.Last())
propertyToSet.SetValue(target, value)
End Sub

Using classes for JSON serialization

All,
I need some help with understanding how classes can work with vb.NET and JSON.NET. I'm completely new to this. I've tried searching for answers, but I'm probably not asking the right questions. Here's my dilemma:
I have a JSON that I need to send to a REST API.
{
"paInfo":[
{
"providerAccountName":"someClient",
"providerAccountDescription":"A fine client.",
"providerName":"provider",
"externalProviderIdentifier":"BU4377890111"
},
{
"providerAccountName":"someClient1",
"providerAccountDescription":"A fine client.",
"providerName":"provider",
"externalProviderIdentifier":"BU4377890111"
}
],
"hubAccountName":"test"
}
I ran this through https://jsonutils.com/ to build my class as:
Public Class PaInfo
Public Property providerAccountName As String
Public Property providerAccountDescription As String
Public Property providerName As String
Public Property externalProviderIdentifier As String
End Class
Public Class addHubAcct
Public Property paInfo As PaInfo()
Public Property hubAccountName As String
End Class
From there, I'm trying to assign values to the class properties, but I don't quite understand how to pass the values for PaInfo to the property. Below is a snippet of code I'm using to assign values. If I try to assign a.paInfo = p, it errors:
error BC30311: Value of type 'PaInfo' cannot be converted to
'PaInfo()'
If I don't pass anything through to a.paInfo, I get a zero-length string in the JSON serialization.
Private Sub serializeAcct()
Dim p As New PaInfo
Dim a As New addHubAcct
p.providerAccountName = "Test\name'This ""that and the other'"
p.providerAccountDescription = "acct desc"
p.providerName = "tester"
p.externalProviderIdentifier = "123456"
a.hubAccountName = "Tester"
a.paInfo = p 'Here's my hangup
Dim o As String = JsonConvert.SerializeObject(a)
Dim deserializedProduct As addHubAcct = JsonConvert.DeserializeObject(Of addHubAcct)(o)
Stop
End Sub
?o.tostring,nq
{"paInfo":null,"hubAccountName":"Tester"}
Change the addHubAcct class like this:
Public Class addHubAcct
Public Property paInfo As New List(Of PaInfo)()
Public Property hubAccountName As String
End Class
And then change the bad line in serializeAcct() like this:
a.paInfo.Add(p)
You likely have other problems as well, but that should get you past the current obstacle.
Using List and .ToArray is what I was missing with my original code.
Private Sub serializeAcct()
Dim p1 As New PaInfo
Dim ps As New List(Of PaInfo)
Dim a As New addHubAcct
p1.providerAccountName = "Test\name'This ""that and the other'"
p1.providerAccountDescription = "acct desc"
p1.providerName = "tester"
p1.externalProviderIdentifier = "123456"
ps.Add(p1)
a.hubAccountName = "Tester"
a.paInfo = ps.ToArray
Dim o As String = JsonConvert.SerializeObject(a)
End Sub

Get specific value from .txt file using identifier VB.Net

I try to create a config file using .txt files, here I find it difficult to read the contents of the format.. already from yesterday I searched on google , but no similar case like me or maybe I missed it..
contents of .txt I have is as follows :
Cek Server IP = 192.168.10.1
Server IP = 192.168.10.1
Cek My Website = www.google.com
My Website = www.anothersite.com
this is my code :
WebControl.Source = New Uri("about:blank")
If My.Computer.Network.Ping("XXX") Then
WebControl.Source = New Uri("ZZZ")
Else
MsgBox("CANNOT CONNECT TO SERVER")
Exit Sub
End If
what i want is how to get value "192.168.10.1" From "Cek Server IP" then send to "XXX" and Get Value "192.168.10.1" from "Server IP" then send to "ZZZ"
How can i do that?
Sory for my bad english. Thanks.
As per my understanding, you want to read the values from your .txt file by giving its key. For that, you will have to write a function first that gets a key as a parameter and return the value:
private String GetValue(String key)
{
Boolean isValueFound = false;
String line = null;
//Open your file
using (StreamReader sr = new StreamReader("YourFile.txt"))
{
//Read it line-by-line
while ((line = sr.ReadLine()) != null)
{
//When the required line is found, set the flag and come out of the loop
if (line.Trim().StartsWith(key))
{
isValueFound = true;
break;
}
}
}
if (isValueFound)
{
//Split the line by using = as separator. So at index 0, you have the key and at index 1 you have the value
String[] strArray = line.Split('=');
//Trim the value before returning to get rid of extra spaces
return strArray[1].Trim();
}
else
{
//if value is not found, return null
return null;
}
}
Now you can call the above function like this:
//This line will give you 192.168.10.1
String result = this.GetValue("Cek Server IP");
//This line will return www.google.com
result = this.GetValue("Cek My Website");
For file I/O, the System.IO.File class has some useful methods, and for text files, the ReadLines method is probably what you want. You can then use String.Contains to check for the = character, and String.Split to separate the lines into key and value parts.
You could wrap this up into a class to read and parse your configuration file, and give you access to the specific values, e.g. (you will probably need some Imports and Option Infer On):
Public Class SettingsFile
Private ReadOnly _settings As IDictionary(Of String, String)
Private Sub New(settings As IDictionary(Of String, String))
_settings = settings
End Sub
Public Default ReadOnly Property Item(name As String) As String
Get
Dim value As String = Nothing
_settings.TryGetValue(name, value)
Return value
End Get
End Property
Public Shared Function Load(fileName As String) As SettingsFile
Dim settings = New Dictionary(Of String, String)()
For Each line In File.ReadLines(fileName).Where(Function(x) x.Contains("="))
Dim parts = line.Split("="c)
If parts.Count = 2 Then
settings(parts(0).Trim()) = parts(1).Trim()
End If
Next
Return New SettingsFile(settings)
End Function
End Class
You could then use this class in your code, e.g.:
Dim s = SettingsFile.Load("C:\Path\To\Settings.txt")
Dim s1 = s("Cek Server IP") ' 192.168.10.1
Dim s2 = s("Cek My Website") ' www.google.com
Dim s3 = s("Bad Key") ' Nothing

how to sort list with strings containing numbers?

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