4

Is it possible to call a delegate stored in a variable by its variable name (as a string)? I guess I'd have to use reflection mechanism, but I'm not getting anywhere

Example code:

class Demo {
  public delegate int DemoDelegate();

  private static int One() {
    return 1;
  }

  private static void CallDelegate(string name) {
    // somehow get the value of the variable with the name
    // stored in "name" and call the delegate using reflection
  }

  private static void CallDelegate(string name, DemoDelegate d) {
    d();
  }

  static void main(string[] args) {
    DemoDelegate one = Demo.One;
    CallDelegate(one);
    // this works, but I want to avoid writing the name of the variable/delegate twice:
    CallDelegate("one", one);
  }

}

Is this even possible? If so how?

8
  • Having DemoDelegate d in the second overload completely defeats the purpose of string name, doesn't it? Commented May 15, 2011 at 19:08
  • @boltclock: yes, that's why i want to avoid it (in my real code, i want to store the name of the variable to Console.Out.WriteLine() it later) Commented May 15, 2011 at 19:14
  • There are a number of fundamental errors here. One() is an instance method for one and you're accessing this from within a static method. What are you trying to call? The instance method One() or the delegate stored in the local variable in main(), one? Commented May 15, 2011 at 19:24
  • @knittl if you only want to store the name of the variable, why not just use "this.delegateMember.Method.Name"? this makes more sense to me than doing dodgy reflection hacks? Commented May 15, 2011 at 19:26
  • @jeff: thanks for mentioning, fixed it. and i want to call the delegate stored in the local variable "one" (lowercase) Commented May 15, 2011 at 19:28

5 Answers 5

7

Variables barely exist. The only way to reliably call-by-string (in this scenario) would be to store the delegates in a dictionary:

Dictionary<string, DemoDelegate> calls = new Dictionary<string, DemoDelegate>
{
    {"one",one}, {"two",two}
}

Now store that dictionary somewhere (in a field, typically), and do something like:

private int CallDelegate(string name) {
    return calls[name].Invoke(); // <==== args there if needed
}
Sign up to request clarification or add additional context in comments.

3 Comments

This is quite not true. It is possible to use variable outside their native contexts using closures (whatever the name is, in C# they are called delegates, lamdas, etc..).
This fact combined with linq expressions, makes the compiler "print" info I want about a variable, using the lamda: () => varIWishToGetInfo.
@Miguel well, you can... sometimes. Don't try it from F# though ;p In reality, I don't think I recommend it
2

Yes, it is possible, as long as you use Linq Expressions, and little reflection.

Take a look at this code, it does something simillar to what I think you want:

using System;
using System.Linq.Expressions;
using System.Reflection;
using System.Collections.Generic;

namespace q6010555
{
    class Demo
    {
        static List<string> varNamesUsed = new List<string>();

        public delegate int DemoDelegate();

        private static int One()
        {
            return 1;
        }
        private static void CallDelegate(Expression<Func<DemoDelegate>> expr)
        {
            var lambda = expr as LambdaExpression;
            var body = lambda.Body;
            var field = body as MemberExpression;
            var name = field.Member.Name;
            var constant = field.Expression as ConstantExpression;
            var value = (DemoDelegate)((field.Member as FieldInfo).GetValue(constant.Value));

            // now you have the variable name... you may use it somehow!
            // You could log the variable name.
            varNamesUsed.Add(name);

            value();
        }
        static void Main(string[] args)
        {
            DemoDelegate one = Demo.One;
            CallDelegate(() => one);

            // show used variable names
            foreach (var item in varNamesUsed)
                Console.WriteLine(item);
            Console.ReadKey();
        }
    }
}

3 Comments

where is a delegate called from its name?
I have changed my answer, including the delegate call. But I don't understand yet, why you need the name of the variable. Is it for logging?
Or, maybe I have misunderstood the question.
0

You can't really access variables in another stack frame (although I think it is possible using hackery around the StackFrame class). Instead, you'll be wanting to pass an Delegate object around and use methods like DynamicInvoke, if you want to invoke a generalised delegate in a reflection-like manner.

Comments

0
public void Fire(string name)
        {
            FieldInfo field = this.GetType().GetField(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

            if (field != null)
            {
                Delegate method = field.GetValue(this) as Delegate;

                if (method != null)
                {
                    method.Method.Invoke(method.Target, new object[0]);
                }
            }
        }

Obviously restricts you from having parameterized delegates.

3 Comments

this works for delegates stored in member variables, but not for local variables, if i understand correctly?
@knittl: If you're using local variables, you should know their name already. In that case, you could just use a switch or a Dictionary (which is what Marc suggests in his answer.
@brian: local variables before the function call. i know then mase, but my code does not ;)
0

I cannot remember what I wanted to achieve more than 10 years ago, but reading the question now, I want to present a potential workaround. The workaround doesn't completely avoid the duplication, but it gets rid of manually stringifying the name of the variable.

The nameof expression allows to produce the name of a variable, type, or member.

static void main(string[] args) {
  DemoDelegate one = Demo.One;
  CallDelegate(one);
  CallDelegate(nameof(one), one);
}

The identifier is still repeated, but at least now changing the name of the variable with a refactoring tool will change the name used for logging too. It is now impossible to forget to update the name used in logging, since that would result in a compilation error ("unknown identifier").

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.