C#动态执行函数的名称?

时间:2012-11-28 13:45:03

标签: c# .net dynamic .net-4.0

我有一个动态变量

dynamic d = GetSomeObject();

将来某个时候,用户会向我发送一个执行功能(name),例如"UsersGetAll"

所以我需要做一些事情:d.UsersGetAll()

我可以用反射来做。但我想使用DLR。

执行此操作的唯一解决方案是MyObject继承DynamicObject然后实施TryInvokeMember吗?

如果我无法掌控课程怎么办?

2 个答案:

答案 0 :(得分:1)

  

我可以用反射来做。但我想使用DLR。

为什么呢?假设这是一个实际上不会动态响应的“普通”对象,那么反射将是最简单的方法。

C#4中的dynamic功能(就语言功能而言)绝对没有任何帮助。它只允许在C#源代码中动态绑定成员名称​​。

现在你可以

  • 启动IronPython会话,并使用动态绑定创建一个微小的Python脚本来调用该方法。
  • 使用CSharpCodeProvider使用dynamic编译一些带有相关方法名称的C#代码,然后执行该代码。
  • 查看d.UsersGetAll()调用的生成代码,并基本上模拟它。

所有这些选项都可能比反射更难,如果您只想要它,那么在“普通”对象上调用“普通”方法,并且您恰好只知道执行时的名称。

答案 1 :(得分:1)

正如Jon所说,如果您怀疑 类型在运行时通过DLR提供方法,则以下内容才适用;在大多数简单的情况下,反射会更容易。

当您知道方法名称而非目标时,

dynamic是预期的。如果您不知道方法名称,那就是tricker。或许,棘手的一点是确保您保留呼叫站点以便可以重复使用(这是DLR保持性能的方式)。一种厚颜无耻的方式是静态实用程序类,它跟踪调用的方法。这是一个例子 - 请注意,如果您需要处理参数,它会变得更加混乱:

using Microsoft.CSharp.RuntimeBinder;
using System;
using System.Collections;
using System.Runtime.CompilerServices;
public class Foo
{
    public object Bar() { return "I was here"; }
}
static class Program
{
    static void Main()
    {
        object obj = new Foo();
        object result = DynamicCallWrapper.Invoke(obj, "Bar");
        Console.WriteLine(result);
    }
}

static class DynamicCallWrapper
{
    // Hashtable has nice threading semantics
    private static readonly Hashtable cache = new Hashtable();
    public static object Invoke(object target, string methodName)
    {
        object found = cache[methodName];
        if (found == null)
        {
            lock (cache)
            {
                found = cache[methodName];
                if(found == null)
                {
                    cache[methodName] = found = CreateCallSite(methodName);
                }
            }
        }
        var callsite = (CallSite<Func<CallSite, object,object>>)found;
        return callsite.Target(callsite, target);
    }
    static object CreateCallSite(string methodName)
    {
        return CallSite<Func<CallSite, object, object>>.Create(
            Binder.InvokeMember(
            CSharpBinderFlags.None, methodName, null, typeof(object),
            new CSharpArgumentInfo[] {
                CSharpArgumentInfo.Create(
                     CSharpArgumentInfoFlags.None, null) }));

    }
}