Tho*_*que 8 reflection dynamic-language-runtime dynamic .net-4.0 c#-4.0
我正在寻找一种动态添加成员动态对象的方法.好的,我想需要一点澄清......
当你这样做:
dynamic foo = new ExpandoObject();
foo.Bar = 42;
Run Code Online (Sandbox Code Playgroud)
该Bar
属性将在运行时动态添加.但代码仍然"静态"引用Bar(名称"Bar"是硬编码的)...如果我想在运行时添加属性而不知道它在编译时的名称怎么办?
我知道如何使用类的方法使用自定义动态对象(我实际上是几个月前的博客)DynamicObject
,但是如何使用任何动态对象?
我可以使用IDynamicMetaObjectProvider
界面,但我不明白如何使用它.例如,我应该将哪个参数传递给GetMetaObject
方法?(它期待一个Expression
)
顺便说一句,你如何对动态对象进行反射?"定期"反思TypeDescriptor
并不显示动态成员......
任何见解将不胜感激!
你想要的是类似于Python的getattr/setattr函数.在C#或VB.NET中没有内置的等效方法.DLR的外层(在Microsoft.Scripting.dll中附带IronPython和IronRuby)包含一组托管API,其中包括具有GetMember/SetMember方法的ObjectOperations API.您可以使用这些,但您需要DLR和基于DLR的语言的额外依赖.
可能最简单的方法是创建一个带有现有C#绑定器的CallSite.您可以通过查看ildasm或反射器中"foo.Bar = 42"的结果来获取此代码.但一个简单的例子是:
object x = new ExpandoObject();
CallSite<Func<CallSite, object, object, object>> site = CallSite<Func<CallSite, object, object, object>>.Create(
Binder.SetMember(
Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags.None,
"Foo",
null,
new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }
)
);
site.Target(site, x, 42);
Console.WriteLine(((dynamic)x).Foo);
Run Code Online (Sandbox Code Playgroud)
开源框架Dynamitey将执行此操作(可通过nuget获得).它封装了同时仍然缓存@ Dino-Viehland使用的调用站点和绑定器代码.
Dynamic.InvokeSet(foo,"Bar",42);
Run Code Online (Sandbox Code Playgroud)
它也可以调用许多其他类型的c#binder.
小智 5
ExpandoObject虽然显式地实现了IDictionary <string,object>.这意味着你可以简单地将ExpandoObject强制转换为IDictionary <string,object>并操纵字典.
dynamic foo = new ExpandoObject();
foo.Bar = 42;
food = (IDictionary<string,object>)foo;
food["Baz"] = 54
Run Code Online (Sandbox Code Playgroud)