我正在实现一个通用函数来从任意提供的动态对象中提取值,但不知道如何调用,TryGetMember
因为它需要一个GetMemberBinder
抽象的,因此我无法创建它.样品...
public object GetValue(DynamicObject Source, string FieldName)
{
object Result = null;
GetMemberBinder Binder = x; // What object must be provided?
Binder.Name = FieldName;
if (Source.TryGetMember(Binder, out Result))
return Result;
throw new Exception("The field '" + FieldName + "' not exists");
}
Run Code Online (Sandbox Code Playgroud)
是否已经存在GetMemberBinder已经存在的具体后代?或者是创建我自己的实现的指南?
Aar*_*ght 55
我不确定框架中是否存在实际返回的任何方法GetMemberBinder
,但这并不重要 - 这不是按名称调用动态成员的正确方法.
您实际需要做的是创建一个呼叫站点.该方法如下所示:
static object GetDynamicMember(object obj, string memberName)
{
var binder = Binder.GetMember(CSharpBinderFlags.None, memberName, obj.GetType(),
new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) });
var callsite = CallSite<Func<CallSite, object, object>>.Create(binder);
return callsite.Target(callsite, obj);
}
Run Code Online (Sandbox Code Playgroud)
注意Binder.GetMember
创建一个CallSiteBinder
,而不是一个GetMemberBinder
.只是要100%清楚.RuntimeBinderException
如果内部调用TryGetMember
失败,此方法将抛出一个,因此您不需要检查结果.如果您不希望调用者看到RuntimeBinderException
它,请将其包装在您自己的try/catch中.
动态调度很复杂,至少相对于静态类型的反射.由于CLR实际上不是动态类型的,因此C#必须实际实例化编译器以确定如何执行成员/方法.那就是创建一个呼叫站点.据我所知,你必须这样做,这就是为什么每个Binder
方法返回一个CallSiteBinder
,你不能直接实例化任何绑定器.
请注意,DLR执行某种呼叫站点缓存,但我不确定自动缓存是否涵盖了这种情况.您很可能希望保存调用站点以供将来调用,以避免不断重新编译的开销.
PS如果您正在使用(或可以使用)ExpandoObject
而不是DynamicObject
记住它实现IDictionary<string, object>
,那么您不需要执行任何此操作.只需将其强制转换为字典类型并检查属性是否存在.我只会曾经使用DynamicObject
过ExpandoObject
,如果我正在做的东西很多不是简单地在运行时添加成员,即改变基础上,运行时绑定的实际行为更加复杂.
jbt*_*ule 14
你不直接调用TryGetMember,你需要的是使用动态api直接通过使用csharp成员绑定器和调用站点来获得相同的效果.
开源框架Dynamitey(通过nuget)使这变得更加容易,因为它有一个静态方法来执行此操作.它适用于任何IDynamicMetaObjectProvider,而不仅仅是DynamicObject和(它适用于比反射更快的常规类型).
return Dynamic.InvokeGet(Source, FieldName);
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
13064 次 |
最近记录: |