如何从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();
}
}
}