SIGN UP MEMBER LOGIN:    
ARTICLE

Setting Enum's Through Reflection

Posted by bobdain Articles | Articles C# September 25, 2006
Tags: .net, c#, enum, reflection
This article show to solve the problem of how to set an enum type in a dynamically loaded DLL.
Reader Level:

Introduction

My application requires me to load a DLL dynamically at run time, set some properties on a class and then execute a method on the class.  Most of this is pretty straight forward and well documented in any number of articles on reflection. 

The tricky part is that one of the properties I need to set is an enum type that is defined within the DLL that I'm loading.  I need to get the enum item values from the DLL, then I need to use those values to set an enum variable in the DLL.  And because I'm loading it dynamically the type definition for the enum is not available at compile time.

I spent some quality time searching for a way to do this and didn't come up with much except for a couple of message board posts from other people asking about the same thing.  Having figured out how to do it, I thought I'd share the magic with the community.

Background

There is a good article by Eric Gunnerson on how to load DLL's dynamically on MSDN at

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp05162002.asp

I have omitted that aspect of the code from my examples for simplicity.

The Remote DLL

The DLL code looks something like the snippet below.  There is a public enum (BitFields) defining a bunch of named bit field values, and a class with a property (ThirdPartyBitFields) that provides access a variable of the enum type.

using System;

 

namespace ThirdPartyDll

{

          public enum BitFields

          {

                   InitialValue = 0,

                   OneSetting = 1,

                   AnotherSetting = 2,

                   SomethingElse = 4,

                   LastOne = 8

          }

 

          public class ThirdPartyClass

          {

                   private BitFields thirdPartyBitFields = BitFields.InitialValue;

 

                   public ThirdPartyClass()

                   {

                   }

 

                   public BitFields ThirdPartyBitFields

                   {

                             get { return this.thirdPartyBitFields; }

                             set { this.thirdPartyBitFields = value; }

                   }

 

                   public void DoSomeGood()

                   {

                             // Make some decisions based on the value

                             // of thirdPartyBitFields

                   }

          }

}

The Easy Way

If I wasn't loading the DLL dynamically then I would simply "Or-Equal" the enum values into the enum variable, like so:

using System;

using ThirdPartyDll;

 

namespace LocalUser

{

          public class LocalUserClass

          {

                   public LocalUserClass()

                   {

                   }

 

                   public void TestTheDll()

                   {

                             ThirdPartyClass myClass = new ThirdPartyClass();

 

                             myClass.ThirdPartyBitFields |= BitFields.AnotherSetting;

                             myClass.ThirdPartyBitFields |= BitFields.SomethingElse;

 

                             myClass.DoSomeGood();

                   }

          }

}
 
The Reflection Way

Unfortunately the easy way isn't an option in my scenario so let's walk through the steps I have to take to accomplish the same thing with reflection.  I'll present the code snippet by snippet to keep it simple, and show the complete method at the end of the article.  Feel free to skip to the end if you just want to see the final result.

The first thing I need to do is load the DLL (which is really an assembly in the .Net world).  I happen to know that the DLL is in the same folder with my executable, so I can load it like this:

AssemblyName name = new AssemblyName();

name.CodeBase = "file://" + Directory.GetCurrentDirectory() + "ThirdPartyDll.dll";

Assembly assembly = AppDomain.CurrentDomain.Load(name);

Next I need to instantiate the class and create a Type object for it.

object theirClass = assembly.CreateInstance("ThirdPartyDll.ThirdPartyClass");

Type theirType = assembly.GetType("ThirdPartyDll.ThirdPartyClass");

Now I load the enum definition so that I can access the individual enum items that I need.

Type enumType = assembly.GetType("ThirdPartyDll.BitFields");
FieldInfo enumItem1 = enumType.GetField("AnotherSetting");
FieldInfo enumItem2 = enumType.GetField("SomethingElse");

Now we get to the crux of the problem.  I can call GetValue() on the FieldInfo enumItem1 and enumItem2 objects, but GetValue() returns an object.  I need to perform an "OR" operation and I can't do that on an object.  The only way I can perform the "OR" is if I cast the objects into a type that supports that operation.

int enumValue1 = (int)enumItem1.GetValue(enumType);

int enumValue2 = (int)enumItem2.GetValue(enumType);

int currentValue = (int)flagsInfo.GetValue(remoteObject, null);

int newValue = currentValue | enumValue1 | enumValue2;

So now I have an int that contains the correct value, but what good is it?  I can't store an int back in the enum variable because there is a type mismatch between int and enum.  Only an enum item can be stored into an enum type.

The solution is that I can create a new enum object based on the Type class that I have and set its value explicitly to the int value that I calculated.  Here is the magic:

object newEnumValue = Enum.ToObject(enumType, newValue);

Once I have the enum item object created it is a simple matter to store it back to the original enum variable.  Then I just invoke my method and I'm done!

flagsInfo.SetValue(remoteObject, newEnumValue, null);

MethodInfo method = remoteType.GetMethod("DoSomeGood");

Method.Invoke(remoteObject,null);

The Final Solution

Here is the final code for accessing the dynamically loaded DLL with reflection.

using System;

using System.Reflection;

using System.IO;

 

namespace RemoteUser

{

          public class RemoteUserClass

          {

                   public RemoteUserClass()

                   {

                             // Load the remote assembly

                             AssemblyName name = new AssemblyName();

                             name.CodeBase = "file://" + Directory.GetCurrentDirectory() + "ThirdPartyDll.dll";

                             Assembly assembly = AppDomain.CurrentDomain.Load(name);

 

                             // Instantiate the class

                             object remoteObject = assembly.CreateInstance("ThirdPartyDll.ThirdPartyClass");

                             Type remoteType = assembly.GetType("ThirdPartyDll.ThirdPartyClass");

 

                             // Load the enum type

                             PropertyInfo flagsInfo = remoteType.GetProperty("ThirdPartyBitFields");

                             Type enumType = assembly.GetType("ThirdPartyDll.BitFields");

 

                             // Load the enum values

                             FieldInfo enumItem1 = enumType.GetField("AnotherSetting");

                             FieldInfo enumItem2 = enumType.GetField("SomethingElse");

 

                             // Calculate the new value

                             int enumValue1 = (int)enumItem1.GetValue(enumType);

                             int enumValue2 = (int)enumItem2.GetValue(enumType);

                             int currentValue = (int)flagsInfo.GetValue(remoteObject, null);

                             int newValue = currentValue | enumValue1 | enumValue2;

                            

                             // Store the new value back in Options.FieldFlags

                             object newEnumValue = Enum.ToObject(enumType, newValue);

                             flagsInfo.SetValue(remoteObject, newEnumValue, null);

 

                             // Call the method

                             MethodInfo method = remoteType.GetMethod("DoSomeGood");

                             Method.Invoke(remoteObject,null);

                   }

          }

}

Login to add your contents and source code to this article
share this article :
post comment
 

Since the solution is using reflection we can't assume the enum underlying type. Enums can be created with any integral types (enum MyTasks : long) except char. So it might be a problem to convert its values to int.

Posted by Andre Slenko Feb 18, 2010

Excellent article, well explained! I've been tearing my hair out trying to work with Enum values entirely by refletion, exactly as you describe - major headache just cured. Brillian!

Posted by Alexander Harris Aug 18, 2008

Excellent article, well explained! I've been tearing my hair out trying to work with Enum values entirely by refletion, exactly as you describe - major headache just cured. Brillian!

Posted by Alexander Harris Aug 18, 2008

Excellent article, well explained! I've been tearing my hair out trying to work with Enum values entirely by refletion, exactly as you describe - major headache just cured. Brillian!

Posted by Alexander Harris Aug 18, 2008

I think what you describe is getting close to what I am trying to do. I am invoking a method on the user control for which I have created an instance from the assembly. One of the parameters of the method is an Enum defined in another type in the assembly. The array of arguments needs to be properly typed and I can do this for the system type parameters but am still working on how to do for the Enum. Any suggestions you might have would be appreciated.

Posted by Alan Haskins Nov 08, 2007
Nevron Gauge for SharePoint
Become a Sponsor
PREMIUM SPONSORS
  • ceTE software specializes in components for dynamic PDF generation and manipulation. The DynamicPDF™ product line allows you to dynamically generate PDF documents, merge PDF documents and new content to existing PDF documents from within your applications. Visit DynamicPDF here
    The leading .NET charting control now features PDF, Flash and Silverlight export, visualization of large datasets and more. Deliver true charting functionality to your BI, Scorecard, Presentation or Scientific apps. Download evaluation now.
Become a Sponsor