Click here to Skip to main content
15,884,099 members
Articles / Programming Languages / C#
Article

Setting Enum's Through Reflection

Rate me:
Please Sign up or sign in to vote.
4.15/5 (21 votes)
23 Aug 20063 min read 62.7K   28   3
Solves the problem of how to set an enum type in a dynamically loaded DLL.

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 straightforward 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, and then I need to use those values to set an enum variable in the DLL. 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

MSDN has a good article by Eric Gunnerson on how to load DLLs dynamically. I have omitted that aspect of the code from my examples, for simplicity. The MSDN article can be found here.

The Remote DLL

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

C#
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:

C#
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 this 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. (If you're the kind of person who reads the last page of a novel first, then feel free to skip to the end.)

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 as my executable, so I can load it like this:

C#
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.

C#
object theirClass = assembly.CreateInstance("ThirdPartyDll.ThirdPartyClass");
Type theirType = assembly.GetType("ThirdPartyDll.ThirdPartyClass");

Now, I load the enum definition so that I can access its individual items, and then access the individual items that I need.

C#
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 operation is if I cast the object into a type that supports that operation.

C#
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 can I do with it? I can’t use SetValue() to store it back in the enum variable because there is a type mismatch between int and enum. The solution is that I can create a new enum object based on the Type class that I have, and set its value explicitly. Here is the magic:

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

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

C#
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.

C#
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);
        }
    }
}

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
AnswerThanks Pin
HelmutBerg19-Dec-11 5:41
HelmutBerg19-Dec-11 5:41 
Generalquestion about how to find the values in an enum Pin
TaLz197811-Sep-08 2:09
TaLz197811-Sep-08 2:09 
GeneralBest article on Reflection so far! Pin
Vladimir Vexler6-Sep-07 0:46
Vladimir Vexler6-Sep-07 0:46 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.