如何从C#中的字符串调用委托?

如何从C#中的字符串调用委托?,c#,.net,string,reflection,delegates,C#,.net,String,Reflection,Delegates,是否可以通过变量名(作为字符串)调用存储在变量中的委托?我想我必须使用反射机制,但我没有任何进展 示例代码: 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 w

是否可以通过变量名(作为字符串)调用存储在变量中的委托?我想我必须使用反射机制,但我没有任何进展

示例代码:

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);
  }

}

这可能吗?如果是,怎么做?如果没有,那么我必须使用第二种形式,bad luck

您不能真正访问另一个堆栈帧中的变量(尽管我认为可以在
堆栈帧
类中使用hackery)。相反,如果您希望以类似反射的方式调用泛化委托,则需要传递一个
委托
对象,并使用类似
DynamicInvoke
的方法。

变量几乎不存在。可靠地按字符串调用(在这种情况下)的唯一方法是将委托存储在字典中:

Dictionary<string, DemoDelegate> calls = new Dictionary<string, DemoDelegate>
{
    {"one",one}, {"two",two}
}
字典调用=新字典
{
{“一”,一},{“二”,二}
}
现在将该词典存储在某个地方(通常存储在一个字段中),并执行如下操作:

private int CallDelegate(string name) {
    return calls[name].Invoke(); // <==== args there if needed
}
private int CallDelegate(字符串名称){
返回调用[name].Invoke();//

显然,限制您使用参数化委托。

是的,这是可能的,只要您使用Linq表达式和少量反射

看看这段代码,它的功能与我认为您想要的类似:

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();
        }
    }
}
使用系统;
使用System.Linq.Expressions;
运用系统反思;
使用System.Collections.Generic;
名称空间q6010555
{
课堂演示
{
静态列表varNamesUsed=新列表();
公共委托int demoelegate();
私有静态int One()
{
返回1;
}
私有静态void CallDelegate(表达式expr)
{
var lambda=expr为LambdaExpression;
var body=lambda.body;
变量字段=主体作为成员表达式;
变量名称=field.Member.name;
var常量=字段。表达式为常量表达式;
var value=(DemoDelegate)((field.Member作为FieldInfo.GetValue(constant.value));
//现在你有了变量名…你可以用它了!
//您可以记录变量名。
varNamesUsed.Add(名称);
value();
}
静态void Main(字符串[]参数)
{
解调器1=演示器1;
CallDelegate(()=>1);
//显示使用过的变量名
foreach(varNamesUsed中的变量项)
控制台写入线(项目);
Console.ReadKey();
}
}
}

在第二次重载中使用
解调器d
完全违背了
字符串名的目的,不是吗?@boltclock:是的,这就是我想避免它的原因(在我的真实代码中,我想将变量名存储到
控制台.Out.WriteLine()
稍后再加载)这里有许多基本错误。
One()
是一个实例方法,您正在从静态方法中访问
。您试图调用什么?实例方法
one()
或存储在
main()
one
?@knittl中的局部变量中的委托如果您只想存储变量的名称,为什么不使用“this.delegateMember.Method.Name”?这对我来说比做诡计多端的反射黑客更有意义?@jeff:谢谢你提到,修复了它。我想调用存储在局部变量“one”(小写)中的委托从其名称中调用代理的位置?我已经更改了答案,包括代理调用。但我还不明白,为什么您需要变量的名称。它是用于日志记录的吗?或者,可能我误解了这个问题。这适用于存储在成员变量中的代理,但不适用于局部变量,如果我理解正确的话?@knittl:如果您不理解的话重新使用局部变量时,您应该已经知道它们的名称。在这种情况下,您可以使用
开关
字典
(这是Marc在中的建议。@brian:函数调用前的局部变量。我知道mase,但我的代码不知道;)事实并非如此。可以使用闭包在其本机上下文之外使用变量(无论名称如何,在C#中称为委托、lamdas等)。这一事实与linq表达式相结合,使得编译器使用lamda:()来“打印”我想要的关于变量的信息=>varIWishToGetInfo.@Miguel嗯,你可以……有时候。不过,不要从F#p尝试,事实上,我不认为我推荐它
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();
        }
    }
}