我有一个动态变量
dynamic d = GetSomeObject();
有时,将来,用户向我发送一个函数来执行(它的name
),例如"UsersGetAll"
所以我需要做类似的事情:d.UsersGetAll()
我可以通过反思来做到这一点。但我想使用 DLR 。
这样做的唯一解决方案是MyObject
继承DynamicObject
然后实现TryInvokeMember
吗?
如果我无法控制班级怎么办?
我可以通过反思来做到这一点。但我想使用 DLR。
为什么?假设这是一个“正常”对象,实际上不会动态响应,反射将是这里最简单的方法。
dynamic
C# 4 中的特性(就语言特性而言)在这里对您没有任何帮助。它只允许在 C# 源代码中动态绑定成员名称。
现在你可以:
CSharpCodeProvider
编译一些 C# 代码,然后执行该代码。dynamic
d.UsersGetAll()
调用生成的代码,并基本上模拟它。所有这些选项都可能比反射更难,如果你想要它,所以在“普通”对象上调用“普通”方法,而你碰巧只在执行时知道名称。
正如 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) }));
}
}