考虑以下代码
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);
通过反射,我可以获得 Users 的值,而它是一个 private 类的列表。现在我想对用户调用 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
是私有(private)的。
2. 在 object { List<InaccessibleClass> }
上调用公共(public) List 方法的正确方法是什么? ?
最佳答案
- Why I can't call Clear() when cast usersOfSample into dynamic?
因为
1.1 During runtime, is usersOfSampleDyn resolved as a List<T> or a object { List<T> }?
是object {List<T>}
.
编辑:
The reason dynamic treats the object as object is that dynamic will be treated as the most derived type that is accessible to where it is called.
如 Jon Hanna's comment 中所述.
1.2 If usersOfSampleDyn was resolved as a object { List<T> }, how to convert it into List or anything I can call Clear() on?
List<T>
实现非泛型 IList
,简单地转换为它:
((IList)usersOfSample).Clear();
- What's the correct way to call a public List method on object { List<InaccessibleClass> }?
你不知道。如果类(class)无法访问,那么这样做是有原因的。如果是您自己的代码,请更改对象可见性,否则不要在外部代码的内部状态中乱搞,它可能会在任何时候中断并产生意想不到且难以调试的副作用。
但如果您真的需要它,可以反射或转换为 IList。
关于c# - 调用对象实际类型的公共(public)方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51532079/