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.
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()
{
}
}
}
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 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:
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 its individual items, and then access the individual 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 operation is if I cast the object
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 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:
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!
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()
{
AssemblyName name = new AssemblyName();
name.CodeBase = "file://" + Directory.GetCurrentDirectory() +
"ThirdPartyDll.dll";
Assembly assembly = AppDomain.CurrentDomain.Load(name);
object remoteObject =
assembly.CreateInstance("ThirdPartyDll.ThirdPartyClass");
Type remoteType =
assembly.GetType("ThirdPartyDll.ThirdPartyClass");
PropertyInfo flagsInfo =
remoteType.GetProperty("ThirdPartyBitFields");
Type enumType = assembly.GetType("ThirdPartyDll.BitFields");
FieldInfo enumItem1 = enumType.GetField("AnotherSetting");
FieldInfo enumItem2 = enumType.GetField("SomethingElse");
int enumValue1 = (int)enumItem1.GetValue(enumType);
int enumValue2 = (int)enumItem2.GetValue(enumType);
int currentValue = (int)flagsInfo.GetValue(remoteObject, null);
int newValue = currentValue | enumValue1 | enumValue2;
object newEnumValue = Enum.ToObject(enumType, newValue);
flagsInfo.SetValue(remoteObject, newEnumValue, null);
MethodInfo method = remoteType.GetMethod("DoSomeGood");
method.Invoke(remoteObject, null);
}
}
}