Rodrigo Alves
Rodrigo Alves

Reputation: 35

How to pass an enum value to the constructor of a class through reflection?

i have the class:

public enum ProviderType { SqlClient, OracleClient};

public class ExternalClass
{
    private string field1;
    private string field2;
    private string EnumsDependance;

    public ExternalClass(string p1, string p2, ProviderType type)
    {
        this.field1 = p1;
        this.field2 = p2;

        if (type == ProviderType.SqlClient)
        {
            this.EnumsDependance = "SQL TYPE";
        }
        else if (type == ProviderType.OracleClient)
        {
            this.EnumsDependance = "ORACLE TYPE";
        }
        else
        {
            this.EnumsDependance = "NO TYPE";
        }
    }
}

In my program I need to create an instance of this class using reflection, but must pass the constructor of this class the value of the enum, how should I do this?

The program is in a different project ExternalClass and ProviderType, and it must be read by reflection. Here is my sketch:

class Program
{
    static void Main(string[] args)
    {
        //dynamically load assembly from file ExternalDLL.dll
        Assembly assembly = Assembly.LoadFile(@"C:\temp\ExternalDLL.dll");

        //get type of class ProviderType (enum) from just loaded assembly
        Type providerType = assembly.GetType("ExternalDLL.ProviderType");

        //get type of class ExternalClass from just loaded assembly
        Type externalClassType = assembly.GetType("ExternalDLL.ExternalClass");

        //creating an instance of the class ExternalClass, using reflection
        //constructor -> ExternalClass(string p1, string p2, ProviderType type)
        object externalClassInstance = Activator.CreateInstance(externalClassType, new object[]{"param1", 
                                                                                                "param2",
                                                                                                "ENUM VALUE" //how should I pass the value?  
                                                                                                });
    }
}

Upvotes: 2

Views: 3571

Answers (2)

Gediminas Masaitis
Gediminas Masaitis

Reputation: 3212

The solution

If you have an enum's Type and want to create it's instance from it's name, do so by using Enum.Parse. Then you can create your external class instance like this:

object enumInstance = Enum.Parse(providerType, "SqlClient");
object externalClassInstance = Activator.CreateInstance(externalClassType, new object[]{"param1", "param2", enumInstance });

If you want to create an enum's instance from it's value, you can do so by using Enum.ToObject, like this:

object enumInstance = Enum.ToObject(providerType, 0);
object externalClassInstance = Activator.CreateInstance(externalClassType, new object[]{"param1", "param2", enumInstance });

Why can't I just pass an integer?

There seems to be some confusion why using Enum.ToObject is necessary. This is because an Enum is not an Int32, nor does it inherit from it (it couldn't - all structs in .NET are sealed). The confusion comes from the fact that you can cast an integer to a specific enum, and get it's instance:

ProviderType enumInstance = (ProviderType)0; // Works just fine

This works because all enums have an explicit cast operator from Int32. When you do so, internally the enum calls Enum.ToObject. When you call Activator.CreateInstance, it does not try to perform a cast or conversion, and tries to use the integer value as a parameter to the constructor. And since the class being created doesn't contain a constructor which takes an int, you get a MissingMethodException.

Also, enums don't even have to be int based, they can be a byte, sbyte, short, ushort, int (default), uint, long, or ulong. You can read more about it here.


Upvotes: 3

Wazner
Wazner

Reputation: 3102

By value

In C# all enumerations have an underlying type, by default this will be Int32. You can get the underlying type of the enumeration by calling Type.GetEnumUnderlyingType.

When no value has been explicitly defined for enumeration values, they will be assigned sequentially, so in your case, SqlClient will be 0 and OracleClient will be 1.

You can convert a value of the underlying type to the enumeration type using Enum.ToObject.

 object oracleClient = Enum.ToObject(providerType, 1); 
 object inst = Activator.CreateInstance(externalClassType, new object[] { "param1", "param2", oracleClient });

By name

Alternatively, you could use Enum.Parse to get the value by the enumeration value name.

Upvotes: 0

Related Questions