• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1084
  • Last Modified:

Reflection InvokeMember on a Enum

I trying to use Reflection to set the values of a Class.
The Class has 3 fields SortType , SortOrder, SortColumn
They are both Integer, except that both of them are Enum

I'm trying to set the value of the Enum and It won't work, but when on the Integer (SortColumn) it work fine.

When I'm calling InvokeMember on a Enum I get an error : Additional information: Object type cannot be converted to target type.
Public Class ListViewSorter
	Implements System.Collections.IComparer
 
	Public SortType As EnumSortType
	Public SortOrder As System.Windows.Forms.SortOrder
	Public SortColumn As Integer
End Class
 
Public Enum EnumSortType As Integer
	[String] = 0
	[Integer] = 1
	[Date] = 2
End Enum
 
Private Sub InvokeMember(ByVal target As Object, ByVal PropertyName As String, ByVal Value As Object)
	If Not (target Is Nothing Or PropertyName Is Nothing) Then
		Dim obj(0) As Object
		obj(0) = Value
		Value = target.GetType.InvokeMember(PropertyName, BindingFlags.Public Or BindingFlags.Instance Or BindingFlags.SetField, Nothing, target, obj)
	End If
End Sub

Open in new window

0
powlin
Asked:
powlin
  • 4
  • 3
1 Solution
 
omegaomegaDeveloperCommented:
Hello, powlin,

I tried the code from your snippet (using the snippet below) and it worked fine for me, even with a value that was "out-of-range" for SortType.  How are you calling the InvokeMember method?  

Cheers,
Randy

   Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
 
        Dim objTest As New ListViewSorter
 
        InvokeMember(objTest, "SortColumn", 3)
        InvokeMember(objTest, "SortType", EnumSortType.Date)
        InvokeMember(objTest, "SortOrder", 1)
        MsgBox("SortColumn = " & objTest.SortColumn & ", SortType = " & objTest.SortType & ", SortOrder = " & objTest.SortOrder)
 
        InvokeMember(objTest, "SortType", 5)
        MsgBox("SortColumn = " & objTest.SortColumn & ", SortType = " & objTest.SortType & ", SortOrder = " & objTest.SortOrder)

Open in new window

0
 
powlinAuthor Commented:
I tried the same but the difference is that I create a instance of ListViewSorter using CreateInstance from an Assembly
Maybe there's something here that is missing
just change the namespace of ObjectName to test it
Dim ObjectName As String = "Queueing.ListViewSorter"
Dim asm As System.Reflection.Assembly = System.Reflection.Assembly.GetEntryAssembly
Dim obj As Object = asm.CreateInstance("ObjectName)
 
InvokeMember2(obj, "SortColumn", 3) 'WORK
InvokeMember2(obj, "SortType", 2) 'FAIL
InvokeMember2(obj, "SortOrder", 1) 'FAIL

Open in new window

0
 
omegaomegaDeveloperCommented:
Hi, powlin,

I tested again with the change you indicated and, in my case, there was still no problem.  (I did have to make two minor changes.  I had to change ObjectName to reflect the name of my test project, and the leading quotation mark in the third line had to be removed.  The test code is in the attached snippet.)

I'm at a bit of a loss to say why this works for me but not for you.  What version are you using?  (I am using VS 2005.)

Cheers,
Randy

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
 
        ' ''Dim objTest As New ListViewSorter
 
        Dim ObjectName As String = "SettingEnumValue.ListViewSorter"
        Dim asm As System.Reflection.Assembly = System.Reflection.Assembly.GetEntryAssembly
        Dim objTest As Object = asm.CreateInstance(ObjectName)
 
        InvokeMember(objTest, "SortColumn", 3)
        InvokeMember(objTest, "SortType", EnumSortType.Date)
        InvokeMember(objTest, "SortOrder", 1)
 
        MsgBox("SortColumn = " & objTest.SortColumn & ", SortType = " & objTest.SortType & ", SortOrder = " & objTest.SortOrder)
 
        InvokeMember(objTest, "SortType", 5)
        MsgBox("SortColumn = " & objTest.SortColumn & ", SortType = " & objTest.SortType & ", SortOrder = " & objTest.SortOrder)
 
    End Sub

Open in new window

0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
powlinAuthor Commented:
I'm using VB.NET 2003
Maybe because the ListViewSorter and EnumSortType is in an outside project

0
 
powlinAuthor Commented:
Maybe more detail about the Solution
There's 2 Project
One named : Queueing
this project contain the
Enum and the Class ListViewSorter

The other Project is named : RestoreState
It contains : InvokeMember

The code is executed in RestoreState

Queueing has a reference of RestoreState but the not RestoreState

So I can't do :
Dim objTest As New ListViewSorter

but doing  :
Dim objTest As Object = System.Reflection.Assembly.GetEntryAssembly.CreateInstance("Queueing.ListViewSorter")

seem to work
0
 
omegaomegaDeveloperCommented:
Hello, powlin,

To make my testing more complete I reconfigured my projects to match yours.  That is, I created two separate projects named "Queueing" and "RestoreState" (a class library) and divided the code as you specified.  More exactly, my "Queueing" contains a class called ListViewSorter and a form (Form1) with one Button (Button1).  My "RestoreState" contains one class (Class1).  The code for each of these is shown in the snippet.

This code worked without any problem for me -- under VB.NET 2005.

So I tried it under VB.NET 2003.  That resulted in exactly the same error that you are seeing.

I can see two possible solutions.
   1. Switch to a later version of dotNet.
   2. Use a different method to set your enumeration fields.

If you want to pursue the second option, you could try something like the code shown in the sample method named SetMember at the end of the snippet.  This code does work in VB.NET 2003.  The sample code assumes that you are setting fields within the object, which matches the code you have shown.  If you are actually setting true properties, you will need to use GetProperty instead of GetField.

Hope that helps you along the way.

Cheers,
Randy


' Code from Queueing.ListViewSorter:
Public Class ListViewSorter
    ' ''Implements System.Collections.IComparer
    Public SortType As EnumSortType
    Public SortOrder As System.Windows.Forms.SortOrder
    Public SortColumn As Integer
End Class
 
Public Enum EnumSortType As Integer
    [String] = 0
    [Integer] = 1
    [Date] = 2
End Enum
 
' Code from Queueing.Form1:
Public Class Form1
    Inherits System.Windows.Forms.Form
#Region " Windows Form Designer generated code "
 ...omitted...
#End Region
 
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim Tester As New RestoreState.Class1
        Tester.TestInvokeMember()
    End Sub
End Class
 
' Code from RestoreState.Class1:
Option Strict Off
Imports System.Reflection
Public Class Class1
    Private Sub InvokeMember(ByVal target As Object, ByVal PropertyName As String, ByVal Value As Object)
        If Not (target Is Nothing Or PropertyName Is Nothing) Then
            Dim obj(0) As Object
            obj(0) = Value
            Value = target.GetType.InvokeMember(PropertyName, BindingFlags.Public Or BindingFlags.Instance Or _
                                                              BindingFlags.SetField, Nothing, target, obj)
        End If
    End Sub
 
    Public Sub TestInvokeMember()
        Dim ObjectName As String = "Queueing.ListViewSorter"
        Dim asm As System.Reflection.Assembly = System.Reflection.Assembly.GetEntryAssembly
        Dim objTest As Object = asm.CreateInstance(ObjectName)
        InvokeMember(objTest, "SortColumn", 3)
        InvokeMember(objTest, "SortType", 2)
        InvokeMember(objTest, "SortOrder", 1)
        MsgBox("SortColumn = " & objTest.SortColumn & ", SortType = " & objTest.SortType & ", SortOrder = " & objTest.SortOrder)
 
        InvokeMember(objTest, "SortType", 5)
        MsgBox("SortColumn = " & objTest.SortColumn & ", SortType = " & objTest.SortType & ", SortOrder = " & objTest.SortOrder)
 
    End Sub
End Class
 
'================ Suggested alternative code (placed in RestoreState.Class1):
    Private Sub SetMember(ByVal target As Object, ByVal FieldName As String, ByVal Value As Object)
        Dim fdiFound As Reflection.FieldInfo
        fdiFound = target.GetType.GetField(FieldName, Reflection.BindingFlags.Instance Or _
                                                      Reflection.BindingFlags.Static Or _
                                                      Reflection.BindingFlags.NonPublic Or _
                                                      Reflection.BindingFlags.Public)
        If (fdiFound.FieldType.IsEnum) Then
            ' Enumerated values require special treatment.
            fdiFound.SetValue(target, [Enum].Parse(fdiFound.FieldType, Value))
        Else
            fdiFound.SetValue(target, Convert.ChangeType(Value, fdiFound.FieldType))
        End If
    End Sub
 
    Public Sub TestSetMember()
        Dim ObjectName As String = "Queueing.ListViewSorter"
        Dim asm As System.Reflection.Assembly = System.Reflection.Assembly.GetEntryAssembly
        Dim objTest As Object = asm.CreateInstance(ObjectName)
 
        SetMember(objTest, "SortColumn", 3)
        SetMember(objTest, "SortType", 2)
        SetMember(objTest, "SortOrder", 1)
        MsgBox("SortColumn = " & objTest.SortColumn & ", SortType = " & objTest.SortType & ", SortOrder = " & objTest.SortOrder)
 
        SetMember(objTest, "SortType", 5)
        MsgBox("SortColumn = " & objTest.SortColumn & ", SortType = " & objTest.SortType & ", SortOrder = " & objTest.SortOrder)
    End Sub

Open in new window

0
 
powlinAuthor Commented:
Excellent, I have test the FieldInfo before trying InvokeMember and was getting the same error, but the line that solved my problem was

fdiFound.SetValue(target, [Enum].Parse(fdiFound.FieldType, Value))

Thank you very much!
0

Featured Post

[Webinar] Cloud and Mobile-First Strategy

Maybe you’ve fully adopted the cloud since the beginning. Or maybe you started with on-prem resources but are pursuing a “cloud and mobile first” strategy. Getting to that end state has its challenges. Discover how to build out a 100% cloud and mobile IT strategy in this webinar.

  • 4
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now