Link to home
Create AccountLog in
Avatar of mrichmon
mrichmon

asked on

Specify delegate from a variable

I have an object (class) that needs to call a function.  Each instance of the class needs to specify which function to call.

I am assuming that delegates would work for this, but I need to have which delegate to call determined via a property of the object (i.e. it is stored in a variable).  The value of that property will be coming from a varchar field in a database.

How do I parse the variable into the name of the delegate to call.  Do I have to use reflection or is there some other way to do this?
Avatar of kaufmed
kaufmed
Flag of United States of America image

Why not create an interface that contracts which method will always be called. Then you can have a member of the class that holds a pointer to the function to call:
/////////////////////////
// Interface
/////////////////////////
namespace WindowsFormsApplication2
{
    public interface IMyInterface
    {
        void InvokeDelegate();
    }
}

/////////////////////////
// Class
/////////////////////////
using System;

namespace WindowsFormsApplication2
{
    class MyClass : IMyInterface
    {
        private Action myCallback;

        public MyClass(Action functionToExecute)
        {
            this.myCallback = functionToExecute;
        }

        #region IMyInterface Members

        public void InvokeDelegate()
        {
            if (myCallback != null) this.myCallback();
        }

        #endregion
    }
}

/////////////////////////
// Usage
/////////////////////////
using System;
using System.ComponentModel;
using System.Windows.Forms;

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        private MyClass c1;
        private MyClass c2;

        public Form1()
        {
            InitializeComponent();

            this.c1 = new MyClass(Function1);
            this.c2 = new MyClass(Function2);
        }

        public void Function1()
        {
            MessageBox.Show("Function1 executed");
        }

        public void Function2()
        {
            MessageBox.Show("Function2 executed");
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            this.c1.InvokeDelegate();
            this.c2.InvokeDelegate();
        }
    }
}

Open in new window

I would use reflection for this:
IE:
 

public class MyClass
{
    public void Function1()
    {
        //do stuff
    }

    public void Function2()
    {
        //do stuff
    }

    public void Function3()
    {
        //do stuff
    }
}

public class KungFoo
{
     public KungFoo(MyClass paramClass)
     {
          if (true)
          {
               var o = paramClass.GetType().InvokeMember("Function1", BindingFlags.DeclaredOnly Or BindingFlags.Public Or BindingFlags.NonPublic Or BindingFlags.Instance Or BindingFlags.SetProperty, Nothing, obj, New [Object]() {0})

          }
     }
}


//view more here
//http://msdn.microsoft.com/en-us/library/system.type.invokemember(VS.71).aspx

Open in new window

Avatar of mrichmon
mrichmon

ASKER

kaufmed,

I do not see how this will accomplish what I am asking.  How does that allow me to convert a string into the name of the delegate to invoke.


zadeveloper,

Thanks for the opinion.  I have used reflection before, but was hoping for an alternative.  If I use reflection the functions to call will not be inside the class object.  They will be in multiple other locations, so I would have to reflect each dll.  That is why I would prefer a non-reflection method if possible for this scenario.

all,
If it helps this is a web application, not a windows application - sorry I wasn't clear on that.
I misinterpreted the question :\

Sorry.
ASKER CERTIFIED SOLUTION
Avatar of kaufmed
kaufmed
Flag of United States of America image

Link to home
membership
Create an account to see this answer
Signing up is free. No credit card required.
Create Account
Yes that is an option - I did not realize you could specify "Delegate" as the type for the value of a dictionary.
When I tried this it does not work.  When I do the add I get 2 errors:

Error      1      The best overloaded method match for 'System.Collections.Generic.Dictionary<string,System.Delegate>.Add(string, System.Delegate)' has some invalid arguments
Error      2      Argument '2': cannot convert from 'method group' to 'System.Delegate'      

Some code is attached...
class AccessFunctions
{
	static Dictionary<string, Delegate> functionList;
	
	static AccessFunctions()
	{
		functionList = new Dictionary<string, Delegate>();
		functionList.Add("Function1", AccessFunctions.Function1);
	}
	
	// A sample test function
	public static bool Function1(UserClass user)
	{
		return user.LastName.StartsWith("S");
	}
}


// would want to use later from another class as AccessFunctions.functionList["function1"] and send in the currentUser

Open in new window

Okay I fussed with the code some and came up with this to eliminate that error:
class AccessFunctions
{
        private static delegate bool AccessFunction(UserClass user);
        static Dictionary<string, Delegate> functionList;
        
        static AccessFunctions()
        {
                functionList = new Dictionary<string, Delegate>();
                functionList.Add("Function1", new AccessFunction(Function1));
        }
        
        // A sample test function
        public static bool Function1(UserClass user)
        {
                return user.LastName.StartsWith("S");
        }
}

Open in new window

Okay to actually be able to compile and then later call the function later I had to change it to the attached code.

class AccessFunctions
{
        internal delegate bool AccessFunction(UserClass user);
        static Dictionary<string, AccessFunction> functionList;
        
        static AccessFunctions()
        {
                functionList = new Dictionary<string, AccessFunction>();
                functionList.Add("Function1", new AccessFunction(Function1));
        }
        
        // A sample test function
        public static bool Function1(UserClass user)
        {
                return user.LastName.StartsWith("S");
        }
}

Open in new window