考虑以下代码
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方法的正确方法是什么?
答案 0 :(得分:1)
- 为什么在将usersOfSample转换为动态时不能调用Clear()?
因为
1.1在运行时,usersOfSampleDyn是否解析为List
或对象{List }?
它是object {List<T>}
。
编辑:
动态将对象视为对象的原因是,动态将被视为其调用位置可访问的最派生类型。
(如Jon Hanna's comment中所述。
1.2如果将usersOfSampleDyn解析为对象{List
},如何将其转换为List或我可以调用Clear()的任何对象?
List<T>
实现了非通用IList
,只需将其强制转换为它即可:
((IList)usersOfSample).Clear();
- 在对象{List
}上调用公共List方法的正确方法是什么?
你不知道。如果无法访问该类,则出于某种原因这样做。如果它是您自己的代码,请更改对象的可见性,否则请不要在外部代码的内部状态中乱糟糟,它可能随时中断,并具有意想不到且难以调试的副作用。
但是,如果您确实需要反射或转换为IList,则可以使用。