调用对象实际类型的公共方法

时间:2018-07-26 06:11:45

标签: c# dynamic reflection

考虑以下代码

using System.Reflection;
public class Sample { 
    private class User { 
        public string Name; 
    } 
    private List<User> Users = new List<User> { 
        new User() { Name = "Alice" }, 
        new User() { Name = "Bob" } 
    }; 
}
var sample = new Sample();
var usersOfSample = typeof(Sample).GetField("Users", BindingFlags.Instance | 
    BindingFlags.NonPublic).GetValue(sample);

通过反思,我可以获取用户的价值,而它是私有类的列表。现在我要在用户上调用List.Clear()。
我的第一个想法是将其转换为动态。但是,以下代码不符合我的预期。

dynamic usersOfSampleDyn = (usersOfSample as dynamic);
usersOfSampleDyn.Clear();

它抛出RuntimeBinderException。

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'object' does not contain a definition for 'Clear'
at CallSite.Target(Closure , CallSite , Object )
at System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid1[T0](CallSite site, T0 arg0)
at MyCode

稍后我会在C#Interactive中尝试此代码,它显示为

'object' does not contain a definition for 'Clear'
+ System.Dynamic.UpdateDelegates.UpdateAndExecute1<T0, TRet>(System.Runtime.CompilerServices.CallSite, T0)

使用反射调用此方法的工作原理如下

usersOfSample.GetType().GetMethod("Clear").Invoke(usersOfSample, new object[0]);

这是我的问题:
1.为什么在将usersOfSample转换为动态时不能调用Clear()?
1.1在运行时,usersOfSampleDyn是否解析为List<T>object { List<T> }
1.2如果将usersOfSampleDyn解析为object { List<T> },如何将其转换为List<T>或我可以称之为Clear()的任何内容?
注意:T是私有的。
2.在object { List<InaccessibleClass> }上调用公共List方法的正确方法是什么?

1 个答案:

答案 0 :(得分:1)

  
      
  1. 为什么在将usersOfSample转换为动态时不能调用Clear()?
  2.   

因为

  

1.1在运行时,usersOfSampleDyn是否解析为List 或对象{List }?

它是object {List<T>}

编辑:

  

动态将对象视为对象的原因是,动态将被视为其调用位置可访问的最派生类型。

(如Jon Hanna's comment中所述。

  

1.2如果将usersOfSampleDyn解析为对象{List },如何将其转换为List或我可以调用Clear()的任何对象?

List<T>实现了非通用IList,只需将其强制转换为它即可:

((IList)usersOfSample).Clear();
  
      
  1. 在对象{List }上调用公共List方法的正确方法是什么?
  2.   

你不知道。如果无法访问该类,则出于某种原因这样做。如果它是您自己的代码,请更改对象的可见性,否则请不要在外部代码的内部状态中乱糟糟,它可能随时中断,并具有意想不到且难以调试的副作用。

但是,如果您确实需要反射或转换为IList,则可以使用。