StrugglingCoder
StrugglingCoder

Reputation: 5011

Invoking a method through reflection that takes a delegate as an input

I have an Employee Class Defined in a namespace and the snippet goes something like this

delegate  bool IsPromotable (Employee employee);
class Program
{
    public static void Main(string[] args)
    {
        List<Employee> empList = new List<Employee>();
        empList.Add(new Employee() { EmployeeId = 1, EmployeeName = "A", Salary = 7500, Experience = 2 });
        empList.Add(new Employee() { EmployeeId = 2, EmployeeName = "B", Salary = 11500, Experience = 6 });
        empList.Add(new Employee() { EmployeeId = 3, EmployeeName = "C", Salary = 14500, Experience = 5 });
        empList.Add(new Employee() { EmployeeId = 4, EmployeeName = "D", Salary = 10500, Experience = 7 });

        IsPromotable isPromotableObj = new IsPromotable(EnableToPromote);

        Employee EmployeeObj = new Employee();
        EmployeeObj.PromoteEmployees(empList, isPromotableObj);
    }

    public static bool EnableToPromote(Employee employee)
    {
        if (employee.Experience >= 5 && employee.Salary >= 10000)
        {
            return true;
        }
        else
            return false;
    }
}

class Employee
{
    public int EmployeeId { get; set; }
    public string EmployeeName { get; set; }
    public int Salary { get; set; }
    public int Experience { get; set; }

    public void PromoteEmployees(List<Employee> employeeList, IsPromotable isPromotableObj)
    {

        foreach (Employee employee in employeeList)
        {
            if (isPromotableObj(employee)) 
            {
                Console.WriteLine(" {0} will be promoted in the next R.P. Cycle ", employee.EmployeeName);
            }
        }
        Console.ReadKey();
    }
}

Now from a separate class in a separate namespace via reflection I want to get the Class Type and all other type objects related to it. Also I want to invoke the PromoteEmployee() method. How do I do that ?

Console.WriteLine("***************Loading External assembly*************");
Assembly assembly = Assembly.LoadFrom(@"C:\Users\Chiranjib\Documents\visual studio 2012\Projects\DelegatesSampleApplication\DelegatesSampleApplication\bin\Debug\DelegatesSampleApplication.exe");
Type employeeType = assembly.GetType("DelegatesSampleApplication.Employee"); //Gets the System.Type object for the Employee Class from the just loaded assembly with all it's dependencies

object employeeInstance = Activator.CreateInstance(employeeType);//Create an instance of the Employee Class Type
//sets it's properites
Console.WriteLine("***************Setting External assembly propeties for the second instance*************");
object employeeInstance2 = Activator.CreateInstance(employeeType);
//set's it's properties
Console.WriteLine("***************Creating an array list that will hold these employee instances***************");
List<Object> employeeInstanceList = new List<object>();
employeeInstanceList.Add(employeeInstance);
employeeInstanceList.Add(employeeInstance2);
Console.WriteLine("***************Invoking External assembly methods*************");
var agrsDel = new Object[] {(employeeInstance) => return employeeInstance};

dynamic value = employeeType.InvokeMember("PromoteEmployees", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public, null, employeeInstance, new Object[] {employeeInstanceList,args})});
Console.ReadKey();

But the errors I am getting are for agrsDel it cannot covert a lambda expression to an object and secondly object does not contain a definition for employeeId. What am I missing?

Upvotes: 0

Views: 497

Answers (2)

Kapoor
Kapoor

Reputation: 1428

it works fine now so here is the complete code, I just made 2 changes -

1> the list of employees was a list of object, so it generated a mismatch error because PromoteEmployee expected a list of type - Employee. I changed it, so its a generic one now.

2> The suggestion I mentioned above, to use Delegate.CreateDelegate

    Console.WriteLine("***************Loading External assembly*************");
        Assembly assembly = Assembly.LoadFrom(@"CXXXXXX\ClassLibrary1\bin\Debug\ClassLibrary1.dll");
        Type employeeType = assembly.GetType("DelegatesSampleApplication.Employee"); //Gets the System.Type object for the Employee Class from the just loaded assembly with all it's dependencies

        object employeeInstance = Activator.CreateInstance(employeeType);//Create an instance of the Employee Class Type
        Console.WriteLine("***************Loading External assembly properties*************");
        PropertyInfo[] propertyInfoColl =  employeeType.GetProperties();
        foreach(var item in propertyInfoColl)
        {
            Console.WriteLine("Loaded Type Property Name {0} and default value {1}", item.Name, item.GetValue(employeeInstance, null));
        }
        Console.WriteLine("***************Setting External assembly propeties for the first instance*************");
        PropertyInfo employeeId = (PropertyInfo)employeeType.GetProperty("EmployeeId");
        employeeId.SetValue(employeeInstance, 1);
        Console.WriteLine("Employee Id Property value now set to " + employeeId.GetValue(employeeInstance,null));
        PropertyInfo employeeName = (PropertyInfo)employeeType.GetProperty("EmployeeName");
       employeeName.SetValue(employeeInstance, "A");
        Console.WriteLine("Employee Name Property value now set to " + employeeName.GetValue(employeeInstance, null));
        PropertyInfo salary = (PropertyInfo)employeeType.GetProperty("Salary");
        salary.SetValue(employeeInstance, 40000);
        Console.WriteLine("Salary Property value now set to " + salary.GetValue(employeeInstance, null));
        PropertyInfo experience = (PropertyInfo)employeeType.GetProperty("Experience");           
        experience.SetValue(employeeInstance, 3);
        Console.WriteLine("Experience Property value now set to " + experience.GetValue(employeeInstance, null));
        Console.WriteLine("***************Setting External assembly propeties for the second instance*************");
        object employeeInstance2 = Activator.CreateInstance(employeeType);
        PropertyInfo employeeId2 = (PropertyInfo)employeeType.GetProperty("EmployeeId");
        employeeId2.SetValue(employeeInstance2, 2);
        Console.WriteLine("Employee Id Property value now set to " + employeeId2.GetValue(employeeInstance2, null));
        PropertyInfo employeeName2 = (PropertyInfo)employeeType.GetProperty("EmployeeName");
        employeeName2.SetValue(employeeInstance2, "B");
        Console.WriteLine("Employee Name Property value now set to " + employeeName2.GetValue(employeeInstance2, null));
        PropertyInfo salary2 = (PropertyInfo)employeeType.GetProperty("Salary");
        salary2.SetValue(employeeInstance2, 50000);
        Console.WriteLine("Salary Property value now set to " + salary2.GetValue(employeeInstance2, null));
        PropertyInfo experience2 = (PropertyInfo)employeeType.GetProperty("Experience");
        experience2.SetValue(employeeInstance2, 6);
        Console.WriteLine("Experience Property value now set to " + experience2.GetValue(employeeInstance2, null));
        Console.WriteLine("***************Creating an array list that will hold these employee instances***************");

        /// list creation goes here 
        var listType = typeof(List<>);
        var constructedListType = listType.MakeGenericType(employeeType);
        var employeeInstanceListType = Activator.CreateInstance(constructedListType);
        var employeeInstanceListInstance = (IList)Activator.CreateInstance(constructedListType);

        employeeInstanceListInstance.Add(employeeInstance);
        employeeInstanceListInstance.Add(employeeInstance2);
        Console.WriteLine("***************Invoking External assembly methods*************");
        //var agrsDel = new Object[] {(employeeInstance) => return employeeInstance};         

        Delegate validationDelegate;
        try
        {
            Type prog = assembly.GetType("DelegatesSampleApplication.Program");
            Type delegateType = assembly.GetType("DelegatesSampleApplication.IsPromotable");
            // Convert the Arg1 argument to a method
            MethodInfo mi = prog.GetMethod("EnableToPromote",
            BindingFlags.Public | BindingFlags.Static);
            // Create a delegate object that wraps the static method
            validationDelegate = Delegate.CreateDelegate(delegateType, mi);
        }
        catch (ArgumentException)
        {
            Console.WriteLine("Phew... not working" );
            return;
        }



        dynamic value = employeeType.InvokeMember("PromoteEmployees", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public, null, employeeInstance, new Object[] { employeeInstanceListInstance, validationDelegate });

Upvotes: 1

Kapoor
Kapoor

Reputation: 1428

I changed your code to use Delegate.Create delegate. Would this help u ?

        //var agrsDel = new Object[] {(employeeInstance) => return employeeInstance};         

        Delegate validationDelegate;
        try
        {
            Type prog = assembly.GetType("DelegatesSampleApplication.Program");
            Type delegateType = assembly.GetType("DelegatesSampleApplication.IsPromotable");
            // Convert the Arg1 argument to a method
            MethodInfo mi = prog.GetMethod("EnableToPromote",
            BindingFlags.Public | BindingFlags.Static);
            // Create a delegate object that wraps the static method
            validationDelegate = Delegate.CreateDelegate(delegateType, mi);
        }
        catch (ArgumentException)
        {
            Console.WriteLine("Phew... not working" );
            return;
        }

Upvotes: 1

Related Questions