Edward Tanguay
Edward Tanguay

Reputation: 193302

How to pass a method name in order to instantiate a delegate?

In the following example, I want to define a System.Action which executes a specific method that I define at runtime, but how do I pass the method name (or the method itself) so that the Action method can define the delegate to point to that particular method?

I'm currently getting the following error:

'methodName' is a 'variable' but is used like a 'method'

using System;
using System.Collections.Generic;

namespace TestDelegate
{
    class Program
    {
        private delegate void WriteHandler(string message);

        static void Main(string[] args)
        {
            List<string> words = new List<string>() { "one", "two", "three", "four", "five" };
            Action<string> theFunction = WriteMessage("WriteBasic");

            foreach (string word in words)
            {
                theFunction(word);
            }
            Console.ReadLine();
        }

        public static void WriteBasic(string message)
        {
            Console.WriteLine(message);
        }

        public static void WriteAdvanced(string message)
        {
            Console.WriteLine("*** {0} ***", message);
        }

        public static Action<string> WriteMessage(string methodName)
        {
            //gets error: 'methodName' is a 'variable' but is used like a 'method'
            WriteHandler writeIt = new WriteHandler(methodName);

            return new Action<string>(writeIt);
        }

    }
}

Upvotes: 2

Views: 2798

Answers (5)

jonp
jonp

Reputation: 13600

You want Delegate.CreateDelegate. In your specific case, you probabaly want Delegate.CreateDelegate(Type,Type,string):

public static Action<string> WriteMessage(string methodName)
{
  return (Action<string>) Delegate.CreateDelegate (
      typeof(Action<string>),
      typeof(Program),
      methodName);
}

However, as Mladen Mihajlovic asked, why do you want to create a delegate based on a string? It would be much easier -- and checked by the compiler! -- to use C#'s support for implicit conversion from methods to delegates of a matching signature.

Upvotes: 0

Mladen Mihajlovic
Mladen Mihajlovic

Reputation: 6435

You don't need the Delegate declaration or the WriteMessage method. Try the following:

using System;
using System.Collections.Generic;

namespace TestDelegate
{
    class Program
    {
        static void Main(string[] args)
        {
            List<string> words = new List<string>() { "one", "two", "three", "four", "five" };
            Action<string> theFunction = WriteBasic;

            foreach (string word in words)
            {
                theFunction(word);
            }
            Console.ReadLine();
        }

        public static void WriteBasic(string message)
        {
            Console.WriteLine(message);
        }

        public static void WriteAdvanced(string message)
        {
            Console.WriteLine("*** {0} ***", message);
        }

    }
}

Action is already a delegate so you don't need to make another one.

Upvotes: 5

Kirtan
Kirtan

Reputation: 21695

Pass it without quotes -

Action<string> theFunction = WriteMessage(WriteBasic);

Change the signature of "WriteMessage" to -

public static Action<string> WriteMessage(WriteHandler methodName)

Also change the "private" delegate to "public" -

public delegate void WriteHandler(string message); //Edit suggested by Mladen Mihajlovic

Upvotes: 2

Skurmedel
Skurmedel

Reputation: 22149

You could make it work with reflection, but that is not recommended.

Why not make the WriteMessage method take an argument of WriteHandler?

Then you can call it like this (in C# 2+):

WriteMessage(myMethod);

Upvotes: 0

Adam Robinson
Adam Robinson

Reputation: 185643

You can't pass the method like that unless you use reflection. Why not take a WriteHandler as your parameter instead of a string?

Upvotes: 1

Related Questions