我有一个动态变量
dynamic d = GetSomeObject();
有时候,未来的某个时间,用户会向我发送一个要执行的函数(它的name
),例如"UsersGetAll"
所以我需要做类似这样的事情:d.UsersGetAll()
我可以使用反射来实现,但我想使用DLR。
这样做的唯一解决方案是让MyObject
继承自DynamicObject
,然后实现TryInvokeMember
吗?
如果我无法控制该类怎么办?
我有一个动态变量
dynamic d = GetSomeObject();
有时候,未来的某个时间,用户会向我发送一个要执行的函数(它的name
),例如"UsersGetAll"
所以我需要做类似这样的事情:d.UsersGetAll()
我可以使用反射来实现,但我想使用DLR。
这样做的唯一解决方案是让MyObject
继承自DynamicObject
,然后实现TryInvokeMember
吗?
如果我无法控制该类怎么办?
正如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) }));
}
}
dynamic
特性(就语言特性而言)对此毫无帮助。它只允许在C#源代码中动态绑定成员名称。CSharpCodeProvider
编译一些使用dynamic
和相关方法名称的C#代码,然后执行该代码。
- 查看您的d.UsersGetAll()
调用生成的代码,并基本模拟该代码。