调用动态对象上的方法基本上都是GetMethod()。Invoke()?

时间:2015-04-30 01:08:54

标签: c# dynamic reflection

标题基本上是我的问题。在封面下是最后一行:

Type xmlCodecType = typeof(XmlCodec<>).MakeGenericType(typeof(SomeObjectProperty));
dynamic xmlCodec = Activator.CreateInstance(xmlCodecType);
xmlCodec.ReadCollection(xmlCodec.GetCollectionName());

基本上这样做:

MethodInfo method1 = xmlCodec.GetType().GetMethod("ReadCollection");
MethodInfo method2 = xmlCodec.GetType().GetMethod("GetCollectionName");
method1.Invoke(xmlCodec, new obj[] { method2.Invoke(xmlCodec, null) });

执行时??

我写的大部分内容都是使用反射方法,因为它是我习惯的,只是感觉更多'在编译期间捕获错误'传递写类型和对象等。动态是更多的动手。然而,有时候反思可能更难以阅读/跟随,而动态并不总是语言中的关键词,而且大多数都是常见的概念。

2 个答案:

答案 0 :(得分:1)

这里有一小段测试代码:

void Main()
{
    this.DoSomething();
}

private void DoSomething()
{
    Console.WriteLine("Foo");
}

编译成这个IL:

IL_0000:  nop         
IL_0001:  ldarg.0     
IL_0002:  call        UserQuery.DoSomething
IL_0007:  nop         
IL_0008:  ret         

DoSomething:
IL_0000:  nop         
IL_0001:  ldstr       "Foo"
IL_0006:  call        System.Console.WriteLine
IL_000B:  nop         
IL_000C:  ret         

现在,如果我引入dynamic引用:

void Main()
{
    dynamic bar = this;
    bar.DoSomething();
}

private void DoSomething()
{
    Console.WriteLine("Foo");
}

这是IL:

IL_0000:  nop         
IL_0001:  ldarg.0     
IL_0002:  stloc.0     // bar
IL_0003:  ldsfld      UserQuery+<Main>o__SiteContainer0.<>p__Site1
IL_0008:  brtrue.s    IL_0042
IL_000A:  ldc.i4      00 01 00 00 
IL_000F:  ldstr       "DoSomething"
IL_0014:  ldnull      
IL_0015:  ldtoken     UserQuery
IL_001A:  call        System.Type.GetTypeFromHandle
IL_001F:  ldc.i4.1    
IL_0020:  newarr      Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo
IL_0025:  stloc.1     // CS$0$0000
IL_0026:  ldloc.1     // CS$0$0000
IL_0027:  ldc.i4.0    
IL_0028:  ldc.i4.0    
IL_0029:  ldnull      
IL_002A:  call        Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create
IL_002F:  stelem.ref  
IL_0030:  ldloc.1     // CS$0$0000
IL_0031:  call        Microsoft.CSharp.RuntimeBinder.Binder.InvokeMember
IL_0036:  call        System.Runtime.CompilerServices.CallSite<System.Action<System.Runtime.CompilerServices.CallSite,System.Object>>.Create
IL_003B:  stsfld      UserQuery+<Main>o__SiteContainer0.<>p__Site1
IL_0040:  br.s        IL_0042
IL_0042:  ldsfld      UserQuery+<Main>o__SiteContainer0.<>p__Site1
IL_0047:  ldfld       System.Runtime.CompilerServices.CallSite<System.Action<System.Runtime.CompilerServices.CallSite,System.Object>>.Target
IL_004C:  ldsfld      UserQuery+<Main>o__SiteContainer0.<>p__Site1
IL_0051:  ldloc.0     // bar
IL_0052:  callvirt    System.Action<System.Runtime.CompilerServices.CallSite,System.Object>.Invoke
IL_0057:  nop         
IL_0058:  ret         

DoSomething:
IL_0000:  nop         
IL_0001:  ldstr       "Foo"
IL_0006:  call        System.Console.WriteLine
IL_000B:  nop         
IL_000C:  ret         

这反编译为:

private void Main()
{
    object obj = (object)this;
    if (SiteContainer.Site == null)
        SiteContainer.Site = CallSite<Action<CallSite, object>>.Create(Microsoft.CSharp.RuntimeBinder.Binder.InvokeMember(CSharpBinderFlags.ResultDiscarded, "DoSomething", (IEnumerable<Type>)null, typeof(UserQuery), (IEnumerable<CSharpArgumentInfo>) new CSharpArgumentInfo[1]
        {
            CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, (string) null)
        }));
    SiteContainer.Site.Target((CallSite)SiteContainer.Site, obj);
}

private void DoSomething()
{
    Console.WriteLine("Foo");
}

[CompilerGenerated]
private static class SiteContainer
{
    public static CallSite<Action<CallSite, object>> Site;
}

所以,就我所知,究竟是什么叫做。

答案 1 :(得分:0)

不,一个方法不是简单地用这个名字查找的。 (dynamic不仅限于方法,但它也可以用于绑定到fields / properties。)如果有问题的类扩展DynamicObject,实际上可以操作绑定表达式。举个简单的例子:

class DynamicDictionary : DynamicObject {
    private Dictionary<string, object> Dict = /*...*/;

    public override bool TryGetMember(GetMemberBinder binder, out object result) {
        result = Dict[binder.Name];

        return true;
    }
}

现在,如果您运行以下代码:

dynamic dict = new DynamicDictionary();
object o = dict.Abc123;

DynamicDictionary,不会尝试获取字段或属性dict.Abc123,而是尝试查找并返回Dict["Abc123"]

编辑:发现dynamic工作here的更深入的帖子。