通过名称动态执行C#函数?

3

我有一个动态变量

dynamic d = GetSomeObject();

有时候,未来的某个时间,用户会向我发送一个要执行的函数(它的name),例如"UsersGetAll"

所以我需要做类似这样的事情:d.UsersGetAll()

我可以使用反射来实现,但我想使用DLR。

这样做的唯一解决方案是让MyObject继承自DynamicObject,然后实现TryInvokeMember吗?

如果我无法控制该类怎么办?


想要使用DLR的原因是什么?据我所知,“动态”语言特性旨在简化对未知对象的已知方法调用。也许可以通过Roslyn在运行时生成编译代码? - flindeberg
2个回答

1

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

dynamic是在您知道方法名称但不知道目标时使用的。如果您不知道方法名称,则会更加棘手。也许最棘手的部分是确保您保留调用站点,以便可以重新使用它(这就是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) }));

    }
}

1
我可以使用反射来完成。但是我想使用DLR。
为什么?假设这是一个“普通”的对象,实际上不会动态响应,那么反射将是最简单的方法。
C# 4中的dynamic特性(就语言特性而言)对此毫无帮助。它只允许在C#源代码中动态绑定成员名称。
现在你可以:
- 启动一个IronPython会话,并创建一个小的Python脚本来使用动态绑定调用该方法。 - 使用CSharpCodeProvider编译一些使用dynamic和相关方法名称的C#代码,然后执行该代码。 - 查看您的d.UsersGetAll()调用生成的代码,并基本模拟该代码。
如果您只想在“普通”对象上调用“普通”方法,并且恰好只在执行时知道名称,则所有这些选项都可能比反射更难。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接