VB.NET LINQ WHERE query collection with various keys throws KeyNotFoundException - vb.net

I would like to select first element from collection using LINQ WHERE function and lambda, but some elements doesn't have subjected key (only one of them has it) - and so I'm receiving KeyNotFoundException error... ;-/
see collection structure
Is there any way how to solve it?
views.First(Function(x) x("DefaultView").ToString = "TRUE")
... threw an exception of type 'System.Collections.Generic.KeyNotFoundException'
Thanks. #JK

You should be able to do
views.FirstOrDefault(Function(x As Dictionary(Of String, Object))
Return x.ContainsKey("DefaultView") AndAlso x("DefaultView").ToString() = "TRUE"
End Function)
ContainsKey ensures that the Key exists in the Dictionary.
AndAlso will only check the second condition if ContainsKey returns true
x("DefaultView") will no longer error because we know it exists

To avoid double lookup in the dictionary.
views.FirstOrDefault(Function(x)
Dim value
Return x.TryGetValue("DefaultView", value) AndAlso value.ToString() = "TRUE"
End Function)

Related

How to get the type of RuntimePropertyInfo

I need to check null values on several objects, I create a function to iterate through propertys and check values, but I need the type before replacing the value.
Private Function EmptyToNulls(ByRef objeto As Object) As Boolean
For Each PropertyInfo In objeto.GetType().GetProperties()
If PropertyInfo.GetType().Name = "String" Then
If IsNothing(PropertyInfo.GetValue(objeto, Nothing)) Then
PropertyInfo.SetValue(objeto, "")
End If
End If
Next
End Function
The problem is that I´m getting "RuntimePropertyInfo" on
PropertyInfo.GetType().Name
How can I get correctly the type of the property?

Simpler way to check if a parameter is an Array of a specific type?

Currently I have the method below in a class. When it is called, the class only stores the data if it is an array of length 3 with specific constraints on the first two elements.
However, the following code seems clunky and inefficient to me, especially if I'm dealing with larger arrays. However, without using Try blocks I haven't been able to find a better way to do this, and would like to ask here if it is possible.
Overrides Sub output(ByVal data As Object)
Dim array() As Object = TryCast(data, Object())
If Not array Is Nothing AndAlso array.Length = 3 Then
For Each element In array
If Not TypeOf (element) Is Integer Then Return
Next
If Not (array(0) = -1 OrElse array(1) = -1) Then
memory.Add(array)
End If
End If
End Sub
First off - I would suggest that instead of using Return, use Exit Sub as that is more obvious and readable.
Based on your code, I'm assuming that the parameter that is passed to the sub could be something other than an array and if it is an array, it could be an array of mixed objects rather than all the elements being integers or singles. If all the elements in the array are always going to be the same type, then rather than check all elements of the array, you can just check that the first element is an integer type.. (this isn't the same as checking if the value itself is an integer of course. you can still have a Single type with a value of 1)
For example .. replace the above loop with simply
If Not TypeOf (array(0)) Is Integer Then Exit Sub
If the array IS of mixed objects, you could try to speed things up by running that check using a Parallel.ForEach loop instead .. like this
Parallel.ForEach(array,
Sub(element)
If Not TypeOf (element) Is Integer Then
Exit Sub
End If
End Sub)
But - the processing overheads of multi-threading the tiny amount of code in the loop will likely cause a performance decrease. If the code in your actual loop is longer, you may get a benefit.
Yet another way is to use the Array.TrueForAll function. Replace your loop with
If Not System.Array.TrueForAll(array, AddressOf IsIntegerType) Then
Exit Sub
End If
and add a function to return true if the object is an integer ..
Private Function IsIntegerType(value As Object) As Boolean
If TypeOf (value) Is Integer Then
Return True
Else
Return False
End If
End Function
You would have to benchmark these to figure out which is quickest in your own code of course. And check memory usage if that could potentially be a problem.
Maybe this for output Sub. Don't know if it is an improvement.
If data Is Nothing Then Exit Sub
Dim t As Type = data.GetType
Dim a() As Object
If t.IsArray Then
a = DirectCast(data, Object())
If Not (a IsNot Nothing AndAlso a.Length = 3 AndAlso TypeOf a(0) Is Integer) Then
Exit Sub
End If
'other code
If Not (CInt(a(0)) = -1 OrElse CInt(a(1)) = -1) Then
memory.Add(foo)
End If
End If

search for an item in collection type in VB .NET 1.1

I am using VB .NET 1.1 and wanted to make sure if inside a key value pair class "Dates" (collection type) a key by name "TerminationDate" exists.
If Not Dates.Item("TerminationDate") Is Nothing Then
'Do x y z'
End if
But this is throwing an exception:
Argument Index is not a valid value.
I am very new to VB.
Thanks
As you saw, the Contains method was added in the 2.0 Framework so you can't use it. As far as I can tell, there is no way within the 1.1 Framework to look for the existence of a given key. The only way to do this is to try getting the item at that key and swallowing the exception if its not found. This helper method will do that:
Private Shared Function CollectionHasKey(col As Microsoft.VisualBasic.Collection, key As String) As Boolean
Try
Dim O = col.Item(key)
Return True
Catch ex As Exception
Return False
End Try
End Function
To use it:
Dim MyCol As New Microsoft.VisualBasic.Collection()
MyCol.Add(New Date(), "D")
Trace.WriteLine(CollectionHasKey(MyCol, "D"))
Trace.WriteLine(CollectionHasKey(MyCol, "Q"))
Item uses the index value to return the item. Its position in the collection starting from 0. If you want to find it using the key: "TerminationDate" You would use Contains instead. Like:
If Dates.Contains("TerminationDate") Then
'Do stuff
End If
Edited based on comments:
I apologize, I thought because you mentioned key/value you pairs that you had used a specific Collection Type. a Dictionary. If you have a Collection of KeyValuePairs you will have to loop thru each item in order to see if the item you want is present. Like:
Dim Item as keyValuePair = nothing
For i as integer = 0 to Dates.Count -1
if Dates.Item(i).Key = "TerminationDate" Then
Item = Dates.Item(i)
End if
Next
If Not Item Is Nothing Then
'Do stuff
End If
My 1.1 type names may be off for keyValuePair, and I think Count is directly off Collection, but it may be a method off of Items (if Items is a property). I don't have the 1.1 framework installed to check.
Contains is a member of dictionary even in 1.1, and would allow you to find an item by key without the loop. here is more information on that type, if that is something you are interested in:
http://msdn.microsoft.com/en-us/library/system.collections.dictionarybase(v=VS.71).aspx

How to chain a vb.net null coalesce operator?

I have a class Customer which contains the property Extensions which in turn contains the property Any.
I tried to do:
Dim room = If(customer.Extensions.Any.ElementAt(0).InnerText, Nothing)
but it threw an error when it did not find an Extension element in the incoming xml. I thought it would return nothing once it saw that the first expression was Nothing. Do I have to do a multiple if statement in this case?
Yes, you do have to check for at least one element. So what you could do would be:
Dim a = customer.Extensions.Any.FirstOrDefault()
Dim room = If(a Is Nothing, Nothing, a.InnerText)
Depending on the type of customer.Extensions.Any, you could do this:
Dim room = If(customer.Extensions.Any.Count > 0, customer.Extensions.Any(0), Nothing)

ignore null reference exception vb.net

I am coding in vb.net.
At times the data is empty/null this is due to user's input into the db.
i will like to bypass it, however i get no luck.
here is snippet of my code:
If hct.mydbvalue.name IsNot Nothing Then
dr("mydbvalue") = hct.mydbvalue.name
End If
I still get an error:
System.NullReferenceException: Object reference not set to an instance of an object.
is there a way if it is a null value to not do anything?
Both #FishBasketGordo and #Yuck are correct, you need to check the full object path for nullability:
If (hct IsNot Nothing) AndAlso (hct.mydbvalue IsNot Nothing) AndAlso (hct.mydbvalue.name IsNot Nothing) Then
dr("mydbvalue") = hct.mydbvalue.name
End If
You won't get a NullReferenceException from data in the database that's null when using ADO.NET; ADO.NET uses DBNull.Value to represent null, so your null reference is coming from somewhere else. In the code above, your exception could occur if any of the following were null:
hct
hct.mydbvalue
dr
Make sure that the whole chain is not null. If hct or mydbvalue is null, you'll get the exception.
To me this looks like hct.mydbvalue is null, and therefore you can't call "name" on it.
Private Function NullCheck(ByVal inObject As Object, Optional ByVal defaultValue As Object = "") As Object
Dim out As Object
If Not IsDBNull(inObject) Then
out = inObject ' This returns the value that was passed in when it is not null
Else
out = defaultValue ' This ensures that out is something and defaults to ""
End If
Return out
End Function
You should be checking whether hct is Nothing, as well as mydbvalue. If you look at the exception message property, it will tell you which is causing the error.
I'm also solving this problem, but in C#.
On my project we've complex object paths like "RootObject.childObject.LitleObject.TinyObject.StringName"
when any of these objects in the path is null, you'll get a null reference when you try something easy like
if(RootObject.childObject.LitleObject.TinyObject.StringName == "a")
I would be okay if it just works as whole rest of the path will be null.
eg. when childObject = null, then I want also RootObject.childObject.LitleObject.TinyObject.StringName to be null, not null reference exception.
However I've found no solution yet, but there is one new operator which can slightly help you in some null tasks.
a = object.object ?? defaultValue;
operator ?? is something like ISNULL in SQL server. If object on left is null, it returns the object from right.
It also replaces whole function NullCheck posted by Michael above.
Hope this will help a bit.
more info on operators
http://msdn.microsoft.com/en-us/library/ms173224(v=vs.80).aspx
http://msdn.microsoft.com/en-us/library/6a71f45d(v=vs.80).aspx
you're talking about diferent things.
It doesn't matter if you use ISDBNull(x.y), String.IsNullOrEmpty(x.y) or (x.y=null)
The problem is far sooner than your selected function is called.
when X is null, it cannot have a property Y. so when you call
AnyOfYourPrefferedFunctions(x.y);
the error raises during evaluation of x.y (null. doesn't exist), so it stops before the machine actually knows what is the function you want to call.
Probably only way to check this, would be using reflection. But you would need to send string with path and reference to root. so something like:
var v = GetValueThroughReflection(rootObject, "rootObject.path.to.the.last.object");
Then you'll be able to write a function which will go through the object path and find which one is null and handle it accordingly. e.g. returns null.
But when you'll heavy use that function, it can make your application run slower. as you'll use reflection for such simple task as is getting value out of variable.
from VS14+ you can use
If hct?.mydbvalue?.name IsNot Nothing Then
dr("mydbvalue") = hct.mydbvalue.name
End If
Try inserting a IF NOT isdbnull(hct.mydbvalue.name)
The following code checks all values.
If hct IsNot Nothing AndAlso
hct.mydbvalue IsNot Nothing AndAlso
Not String.IsNullOrWhitespace(hct.mydbvalue.name) Then
dr("mydbvalue") = hct.mydbvalue.name
End If
Note that the last test used String.IsNullOrWhitespace(). I'm assuming name is a string and you don't want to save empty strings.
Update 1
The following code is a simple console application to prove that using IsDbNull() or Micheal's NullCheck() will throw NullReferenceException when hct.mydbvalue is Nothing.
Module Module1
Sub Main()
Dim hct = New hct
Dim dr = New Dictionary(Of String, String)
Dim errorCount = 0
Try
Dim thisCallWillFail = IsDBNull(hct.mydbvalue.name)
Catch ex As NullReferenceException
Console.WriteLine(
"Using IsDBNull() threw NullReferenceException as expected."
)
errorCount += 1
End Try
Try
Dim thisCallWillFail = NullCheck(hct.mydbvalue.name)
Catch ex As NullReferenceException
Console.WriteLine(
"Using NullCheck() threw NullReferenceException as expected."
)
errorCount += 1
End Try
Console.WriteLine("errorCount = 2? {0}", errorCount = 2)
End Sub
Private Function NullCheck(ByVal inObject As Object,
Optional ByVal defaultValue As Object = "") As Object
Dim out As Object
If Not IsDBNull(inObject) Then
' This returns the value that was passed in when it is not null
out = inObject
Else
' This ensures that out is something and defaults to ""
out = defaultValue
End If
Return out
End Function
End Module
Public Class hct
Property mydbvalue As mydbvalue
End Class
Public Class mydbvalue
Property name As String
End Class