Getting value from a custom object exception error - vb.net

When I try to assign _val I get "Object does not match target type."
I verified both PropertyInfo's are system.string. I also found examples of this syntax. Thanks for any help.
Private Function SetAttributesForSplitFiles(ByVal _file As String, ByVal _depHeader As HeaderParse)
Dim _fileMask As New FileMaskExtension()
Dim _type As Type = GetType(HeaderParse.depBackupFileProperties)
For Each _prop As Reflection.PropertyInfo In GetType(OutputMgr.Interface.FileMaskExtension).GetProperties()
Dim _headerProperty As PropertyInfo = _type.GetProperty(_prop.Name)
Dim _val = _headerProperty.GetValue(_depHeader)
_prop.SetValue(_fileMask, _val, Nothing)
Next
SendFileTODepcon(_fileMask, _file)
End Function

It was because the custom class I was using was two layers deep.
This worked.
Dim _val As Object = _headerProperty.GetValue(_depHeader.FileProperties)

Related

System.NullReferenceException when doing For...Each on Dictionary Array

I may be incorrectly using the term "Dictionary Array", so please tell me the correct terminology if that is the case. In my code below, what I am referring to as a dictionary array is Dim PdfIndividual(individualCount).
Essentially I am trying to get a lambda function to return a count after it iterates through my dictionary array and finds the value I am trying to get a count for.
I am limited in the framework where this code will eventually run which is why I am using a lambda function in the first place. So while I am sure the code I have presented may not be ideal, I am really just interested in understanding why the error occurs, versus just getting it to work.
Dim relationshipTypeCount As Func(Of Dictionary(Of String, String)(), String, Integer) =
Function(PdfIndividualArray, relationshipType)
Dim dictValue As String = ""
Dim relTypeCountResult As Integer = 0
For Each pdfIndDict As Dictionary(Of String, String) In PdfIndividualArray
pdfIndDict.TryGetValue("RelationshipType", dictValue)
If dictValue = relationshipType Then
relTypeCountResult += 1
End If
Next
Return relTypeCountResult
End Function
Dim individualCount As Integer = 5
Dim relType As String = ""
Dim PdfIndividual(individualCount) As Dictionary(Of String, String)
For i As Integer = 0 To individualCount
If i = 0 Then
relType = "primary"
ElseIf i <= 3 Then
relType = "secondary"
ElseIf i > 3 Then
relType = "guest"
End If
PdfIndividual(i) = New Dictionary(Of String, String)
PdfIndividual(i).Add("RelationshipType", relType)
Dim relCount As Integer = relCount = relationshipTypeCount(PdfIndividual, relType)
Next
The error occurs on the dictionary element in the For...Each of my relationshipTypeCount lambda function.
The error text is:
System.NullReferenceException: 'Object reference not set to an
instance of an object.'
pdfIndDict was Nothing.
Screenshot of the error exception
Depending on your targeted .NET version, you can use the following null-conditional form which is more concise:
For Each pdfIndDict As Dictionary(Of String, String) In PdfIndividualArray
pdfIndDict?.TryGetValue("RelationshipType", dictValue)
If dictValue = relationshipType Then relTypeCountResult += 1
Next pdfIndDict
BTW, you can also use the following null check form:
If pdfIndDict IsNot Nothing Then ...
After debugging further I realized that my issue was that I was iterating over an "array" that had 6 elements, however 5 of the elements were nothing at the time of the first call of the lambda function. So I just needed to add a check that the dictionary element I was handling was not nothing.
For Each pdfIndDict As Dictionary(Of String, String) In PdfIndividualArray
If Not IsNothing(pdfIndDict) Then
pdfIndDict.TryGetValue("RelationshipType", dictValue)
If dictValue = relationshipType Then
relTypeCountResult += 1
End If
End If
Next

Runtime Generated EventHandler of Unknown Type

Ok, so I have been stuck on this for a while, combining various question solutions from on here.
Situation:
I instantiate an Object of Type x by using the activator.CreateInstance(x)
Type x can vary but always has the same properties and methods.
The problem is that type x has an event ReadCompleted as ReadCompleted (this is a delegate), type y has the same event, with the same delegate but it is of type ReadCompleted1, z => ReadCompleted2, etc...
Solution:
I assign a delegate at runtime using the following code:
Dim Client As Object = ServiceProvider.GetService(TypeDict(Entity))
Dim TaskCompletionSource As New TaskCompletionSource(Of Entity)()
Dim addMethod As MethodInfo = Client.GetType().GetMethod("add_ReadCompleted")
Dim removeMethod As MethodInfo = Client.GetType().GetMethod("remove_ReadCompleted")
Dim self As Object = Nothing
Dim getSelf As Func(Of Object) = Function() self
Dim eventArgType As Type = Client.GetType().GetEvent("ReadCompleted").EventHandlerType.GetMethod("Invoke").GetParameters()(1).ParameterType
Dim e As ParameterExpression = Expression.Variable(eventArgType)
Dim ExpBlock As BlockExpression = Expression.Block({Expression.Parameter(GetType(Object)), e},
Expression.Call(
Nothing,
Me.GetType().GetMethod("ProcessTask"),
Expression.Convert(e, eventArgType),
Expression.Constant(TaskCompletionSource)),
Expression.Call(
Expression.Constant(Client),
removeMethod,
Expression.Convert(
Expression.Invoke(
Expression.Constant(getSelf)),
addMethod.GetParameters()(0).ParameterType)
)
)
Dim lambda As LambdaExpression = Expression.Lambda(
addMethod.GetParameters()(0).ParameterType,
ExpBlock,
Expression.Parameter(GetType(Object)),
Expression.Parameter(eventArgType))
Dim dlg As [Delegate] = lambda.Compile()
self = dlg
addMethod.Invoke(Client, {dlg})
Client.ReadAsync(PrimaryKey)
Now my knowledge on linq and it's Expression class is limited and i did my best to research the msdn documentation but i can't figure it out:
the method ProcessTask gets called properly, for which i've worked long enough, but my parameter e is always Nothing, resulting in a NullReferenceException.
The method:
Public Shared Sub ProcessTask(ByVal e, ByRef tcs)
'Console.WriteLine(e.GetType())
If e.Error IsNot Nothing Then
tcs.TrySetException(e.Error)
ElseIf e.Cancelled Then
tcs.TrySetCanceled()
Else
tcs.TrySetResult(e.Result)
End If
End Sub
I have no idea why, according to how i see it this is the correct way to call my method, but obviously it isn't. Can someone point me in the right direction for this?
Could be I'm just plain blind and missing something very obvious....
Thanks in advance!
EDIT:
Whilst awaiting an answer i tried to do some more debugging(which is hell in this scenario) saw that if i do:
Dim s As ParameterExpression = Expression.Variable(GetType(Object), "Sender")
Dim ExpBlock As BlockExpression = Expression.Block({s, e},
Expression.Call(
Nothing,
GetType(Console).GetMethod("WriteLine", New Type() {GetType(String)}),
Expression.Call(s, GetType(Object).GetMethod("ToString"))),
Expression.Call(
Expression.Constant(Client),
removeMethod,
Expression.Convert(
Expression.Invoke(
Expression.Constant(getSelf)),
addMethod.GetParameters()(0).ParameterType)
))
The sender as object parameter is also nothing, so i'm getting the feeling that none of my arguments are getting passed through...
Hope this helps shed more light on the matter.
I figured it out, turns out i misinterpreted the whole parameter thing of Expression:
Dim Client As Object = ServiceProvider.GetService(TypeDict(Entity))
Dim TaskCompletionSource As New TaskCompletionSource(Of Entity)()
Dim addMethod As MethodInfo = Client.GetType().GetMethod("add_ReadCompleted")
Dim removeMethod As MethodInfo = Client.GetType().GetMethod("remove_ReadCompleted")
Dim self As Object = Nothing
Dim getSelf As Func(Of Object) = Function() self
Dim eventArgType As Type = Client.GetType().GetEvent("ReadCompleted").EventHandlerType.GetMethod("Invoke").GetParameters()(1).ParameterType
Dim s As ParameterExpression = Expression.Parameter(GetType(Object), "Sender")
Dim e As ParameterExpression = Expression.Variable(eventArgType, "EventArgs")
Dim ExpBlock As BlockExpression = Expression.Block(\*{Expression.Parameter('GetType(Object)), e},*\ <--- this has to go
Expression.Call(
Nothing,
Me.GetType().GetMethod("ProcessTask"),
Expression.Convert(e, eventArgType),
Expression.Constant(TaskCompletionSource)),
Expression.Call(
Expression.Constant(Client),
removeMethod,
Expression.Convert(
Expression.Invoke(
Expression.Constant(getSelf)),
addMethod.GetParameters()(0).ParameterType)
)
)
Dim lambda As LambdaExpression = Expression.Lambda(
addMethod.GetParameters()(0).ParameterType,
ExpBlock,
s,
e)
\*Expression.Parameter(GetType(Object)),
Expression.Parameter(eventArgType))*\ <-- this has to change
Dim dlg As [Delegate] = lambda.Compile()
self = dlg
addMethod.Invoke(Client, {dlg})
Client.ReadAsync(PrimaryKey)
So as i see it the parameters don't have to be defined in the expression itself, but they sould be created, and the reference should be kept to use them in the lambda in which you compile the expression.
Hope someone in the future has some use for this answer, and thanks to all for taking a look at this.

Too many arguments to '' in VB.net

I'm trying to save from list field that have more than one data on it, how to save all of it at once?
I've try this code
Dim detail As New Detail
Dim detailBr As New DetailBridge
Dim i As Integer
For i = 0 To lstProduct.Items.Count - 1
detail = detailBr.Insert(Convert.ToInt32(ddlGroup.SelectedValue), lstProduct.Items(i).Value) 'error was here
Next
but I got an error in lstProduct.Items(i).Value the error said
Too many arguments to '...'
I'm not sure what the error is.
can anyone help? Thanks for advice.
UPDATE : detailBr is class and the code is
Public Function Insert(ByVal GroupID As Integer, ByVal ProductID As String) As Boolean
Dim iResult As Integer
Dim arrColumn() As String = {"GroupID", "ProductID"}
Dim arrValue() As Object = {GroupID, ProductID}
oConn.Open()
Dim SQLString As String = GenInsert("DetailGroup", arrColumn, arrValue)
Try
iResult = SCommand.Execute(SQLString, oConn)
Catch ex As Exception
Throw ex
Finally
oConn.Close()
End Try
If iResult > 0 Then
Return True
Else
Return False
End If
End Function
The problem here is with the GenInsert Function. Its last two arguments are arrays.
Dim arrColumn() As String = {"GroupID", "ProductID"}
Dim arrValue() As Object = {GroupID, ProductID}
Dim SQLString As String = GenInsert("DetailGroup", arrColumn, arrValue)
A procedure can define only one parameter array, and it must be the last parameter in the procedure definition. MSDN
In simple words you can have only one parameter as array in GenInsert function either arrColumn or arrValue
However, to solve your current problem you can use two dimensional array as parameter as in passing-two-dimensional-array-through-functions and MSDN: Arrays as Return Values and Parameters

Strange error reported in this code, please explain?

I put together this bit of code from a few other samples, and I am getting an error I cant understand. On this line in the code below, on the word Observer,
Dim Results As ManagementObjectCollection = Worker.Get(Observer)
I get the error
"Value of type 'System.Management.ManagementOperationObserver' cannot be converted to 'Integer'"
Can somebody explain what this means?
There are two signatures for ManagementObjectSearcher.Get(), one has no parameters and the other has one parameter, a ManagementOperationObserver for async operation. That is what I am providing, yet the error indicates conversion involving an integer?
Public Shared Sub WMIDriveDetectionASYNC(ByVal args As String())
Dim Observer As New ManagementOperationObserver()
Dim completionHandler As New MyHandler()
AddHandler Observer.Completed, AddressOf completionHandler.Done
Dim Machine = "192.168.0.15"
Dim Scope = New ManagementScope("\\" & Machine & "\root\cimv2")
Dim QueryString = "select Name, Size, FreeSpace from Win32_LogicalDisk where DriveType=3"
Dim Query = New ObjectQuery(QueryString)
Dim Worker = New ManagementObjectSearcher(Scope, Query)
Dim Results As ManagementObjectCollection = Worker.Get(Observer) 'use parameter to make async
For Each item As ManagementObject In Results
Console.WriteLine("{0} {2} {1}", item("Name"), item("FreeSpace"), item("Size"))
Dim FullSpace As Long = (CLng(item("Size")) - CLng(item("FreeSpace"))) \ 1000000
Console.WriteLine(FullSpace)
Next
End Sub
Public Class MyHandler
Private _isComplete As Boolean = False
Public Sub Done(sender As Object, e As CompletedEventArgs)
_isComplete = True
End Sub 'Done
Public ReadOnly Property IsComplete() As Boolean
Get
Return _isComplete
End Get
End Property
End Class
Thanks for any advice!
I think that uses a reference type to get the result and put it in the object you sent as a parameter. So I think it just needs to look like:
Worker.Get(Observer)
instead of trying to set something = to that since it isn't a function that returns a value.
Then use the events you hook up to the object to handle whatever you need to do with the items you find.

VB.NET Generic Function

What I want to do is, based on the type of T do different opperations. Below is a simple example of my problem.
Public Shared Function Example(Of T)() As T
Dim retval As T
If TypeOf retval Is String Then
Dim myString As String = "Hello"
retval = myString
ElseIf TypeOf retval Is Integer Then
Dim myInt As Integer = 101
retval = myInt
End If
Return retval
End Function
I get the error "Value of Type 'String' Cannot be converted to 'T'" Same with the integer part. If I cast either to an object before asigning them to retval it works but I think that would defeat my purpose and be less efficient. Any Ideas? Thanks!
It's probably a bit late, but try this:
Public Shared Function CAnyType(Of T)(ByRef UTO As Object) As T
Return CType(UTO, T)
End Function
Public Shared Function ExecuteSQLstmtScalar(Of T)(ByVal strSQL As String) As T
Dim T_ReturnValue As T
' Here we have the result of a DB query '
Dim obj As Object = "Value from DB query cmd.ExecuteScalar"
Dim strReturnValue As Object = obj.ToString();
Try
Dim tReturnType As Type = GetType(T)
If tReturnType Is GetType(String) Then
Return CAnyType(Of T)(strReturnValue)
ElseIf tReturnType Is GetType(Boolean) Then
Dim bReturnValue As Boolean = Boolean.Parse(strReturnValue)
Return CAnyType(Of T)(bReturnValue)
ElseIf tReturnType Is GetType(Integer) Then
Dim iReturnValue As Integer = Integer.Parse(strReturnValue)
Return CAnyType(Of T)(iReturnValue)
ElseIf tReturnType Is GetType(Long) Then
Dim lngReturnValue As Long = Long.Parse(strReturnValue)
Return CAnyType(Of T)(lngReturnValue)
Else
MsgBox("ExecuteSQLstmtScalar(Of T): This type is not yet defined.")
End If
Catch ex As Exception
End Try
Return Nothing
End Function
(the secrect is casting your generic result to object, then casting from type Object to template type T).
PS:
You are responsible to ensure that your code works correctly with nullable types and NOT nullable types, as well as System.DbNull.Value. For example when string is NULL and return value type is Boolean (not nullable). On a sidenote, please also note that VB Nothing is NOT equal NULL, it's equal to C#'s default(T) (e.g. System.Guid.Empty for Guid)
With a generic method, T will be of exactly one type each time. Let's say that you have code calling Example(Of Integer). Now, in your mind, replace T with Integer. The resulting method will contain these lines (amongst others).
Dim retval As Integer
If TypeOf retval Is String Then
Dim myString As String = "Hello"
retval = myString
' more code follows '
Assigning a String to an integer like that will never work. Sure, that code will also never execute, since the If-block prevents that, but the code will still not compile. (As a side not, the above code will fail to compile because the TypeOf keyword is restricted to use with reference types, but that is another story)
Typically when creating generic methods, you will want to do the same thing with whatever input you get, but in a type safe manner. If you want to have different behavior for different types of input, you are usually better off by overloading the methods instead.
retVal = (T) "Hello World!"
Do retval = Ctype(Mystring, T) or retVal = Ctype(MyInt, T)
An alternative solution is encapsulate this kind of logic in a class and use VB CallByName function:
Class Aux(Of T)
Public Value As T
Private dicc As Dictionary(Of String, Object)
Sub New()
dicc = New Dictionary(Of String, Object)
dicc.Add("system.string", "hola")
dicc.Add("system.int32", 15)
dicc.Add("system.double", 15.0)
End Sub
Public Function Test() As T
Dim typeName As String = GetType(T).ToString.ToLower
If dicc.ContainsKey(typeName) Then
CallByName(Me, "Value", CallType.Set, dicc(typeName))
End If
Return Value
End Function
Protected Overrides Sub Finalize()
MyBase.Finalize()
If Not (dicc Is Nothing) Then dicc.Clear()
dicc = Nothing
End Sub
End Class