Reflection and Enum Conversion

M

Matt Porco

I am trying to figure out how to convert a primitive type (Integer,
Short, etc.) to a corresponding Enum with the same underlying type.
The problem is, I don't know the actual types or Enums at compile time
- only at runtime. I'm using a PropertyInfo object to reflect on a
property of Enum type, and I'm retrieving a number (Integer or
whatever) from a database, then trying to use PropertyInfo.SetValue to
set the value of the property to the number retrieved from the
database. Here's some code:

------------------------------------------------
Option Explicit On
Imports System.Reflection

Class TestClass

Enum TestType As Integer
TypeA = 0
TypeB = 1
TypeC = 2
End Enum

Dim _testField As TestType

Property TestProperty() As TestType
Get
Return _testField
End Get
Set(ByVal Value As TestType)
_testField = Value
End Set
End Property

Shared Function TestPropertyInfo() As PropertyInfo
Dim info As PropertyInfo
info = GetType(TestClass).GetProperty("TestProperty", _
BindingFlags.Instance Or BindingFlags.Public Or
BindingFlags.NonPublic)
Return info
End Function

End Class

Class TestHarness

Sub Main()

Dim obj As New TestClass
GetValueFromDatabase(obj)

End Sub

Sub GetValueFromDatabase(ByVal obj As TestClass)

' This code just builds a DataTable as an illustration - real code
' would query the database and retrieve results.
Dim table As New DataTable("Test")
table.Columns.Add(New DataColumn("IntegerColumn",
GetType(Integer)))
Dim row As DataRow = table.NewRow
row(0) = 212

' get value from retrieved results
Dim value As Object = row(0)
If value.Equals(DBNull.Value) Then
value = Nothing
End If

TestClass.TestPropertyInfo.SetValue(obj, value, Nothing)
' previous line throws the following exception:
' An unhandled exception of type 'System.ArgumentException'
occurred
' in mscorlib.dll
' Additional information: Object type cannot be converted to
target type.

End Sub

End Class
------------------------------------------------

Obviously it's not implicitly converting the Integer to a TestType
since I have Option Explicit On (and turning it off is not a
solution). So how can I convert the returned value's type (Integer)
to the property's type (TestType) at runtime? I tried using
Convert.ChangeType(Object, Type) to convert the returned value to the
type specified by PropertyInfo.PropertyType, but this still throws a
similar exception.

Thanks.

Matt ([email protected])
 
J

Jon Skeet [C# MVP]

Matt Porco said:
I am trying to figure out how to convert a primitive type (Integer,
Short, etc.) to a corresponding Enum with the same underlying type.
The problem is, I don't know the actual types or Enums at compile time
- only at runtime. I'm using a PropertyInfo object to reflect on a
property of Enum type, and I'm retrieving a number (Integer or
whatever) from a database, then trying to use PropertyInfo.SetValue to
set the value of the property to the number retrieved from the
database. Here's some code:

Use Enum.ToObject. Sample code:

using System;

enum Foo
{
Bar = 1
}

class Test
{
static void Main()
{
object x = Enum.ToObject(typeof(Foo), 1);
Console.WriteLine(x.GetType());
Console.WriteLine(x);
}
}
 
M

Matt Porco

Thanks! Worked like a charm.

Matt

Jon Skeet said:
Use Enum.ToObject. Sample code:

using System;

enum Foo
{
Bar = 1
}

class Test
{
static void Main()
{
object x = Enum.ToObject(typeof(Foo), 1);
Console.WriteLine(x.GetType());
Console.WriteLine(x);
}
}
 
G

Guest

I also think that you should check before converting if the value that you are about to convert is defined in the Enum with [Enum].isDefined and raise an exception if the value is "out of range".

Anna
 
G

Guest

I also think that you should check before converting if the value that you are about to convert is defined in the Enum with [Enum].isDefined and raise an exception if the value is "out of range".

Anna
 
G

Guest

I also think that you should check before converting if the value that you are about to convert is defined in the Enum with [Enum].isDefined and raise an exception if the value is "out of range".

Anna
 
J

Jon Skeet [C# MVP]

Anna said:
I also think that you should check before converting if the value
that you are about to convert is defined in the Enum with
[Enum].isDefined and raise an exception if the value is "out of
range".

Well, that depends on the usage model. There are some times when that's
appropriate, and some times when it's not. Certainly worth considering
though.
 
J

Jon Skeet [C# MVP]

Anna said:
I think it is always appropriate because you don't know if the value
that you are going to convert defined in Enum and the conversion
doesn't throw you an exception so you may think everything is ok when
it is not. In your example try to convert 2 - no exception and
Console.WriteLine(x) prints 2 on the screen.

And sometimes that's absolutely fine. Take HttpStatusCode, for example.
There are times that a webserver gives back a non-standard status code
(if it's a private protocol running over HTTP). In those cases, you may
still want to use HttpStatusCode, but have some values which aren't
actually part of the enumeration.
 
J

Jon Skeet [C# MVP]

Anna said:
in this scenario you are right - i just think that people should be
careful with conversion of primitive types to Enum, it didn't behave
the i expected it to - especially if the value you are converting has
to be one of the declared in Enum.

So as I said - it's something to check in *some* situations, but not
all.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top