【问题标题】:Call a public method of a object's actual type调用对象实际类型的公共方法
【发布时间】:2019-01-03 01:13:31
【问题描述】:

考虑下面的代码

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);

通过反射,我可以获得用户的价值,而它是一个 private 类的 List。现在我想对用户调用 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&lt;T&gt; 还是object { List&lt;T&gt; }
1.2 如果 usersOfSampleDyn 被解析为object { List&lt;T&gt; },如何将其转换为List&lt;T&gt; 或我可以调用Clear() 的任何内容?
注意:T 是私有的。
2. 在object { List&lt;InaccessibleClass&gt; } 上调用公共List 方法的正确方法是什么?

【问题讨论】:

  • 我不确定您所说的 dynamic { List&lt;T&gt; } 甚至 dynamic { object { List&lt;T&gt; } } 是什么意思。 usersOfSampleDyn 当然是dynamic,它在运行时的类型被解析为object。但是,如果您能提供您收到的确切错误消息,那就太好了。
  • 如果您知道您正在使用 List&lt;T&gt;,您可以转换为非通用 IList 并使用它。
  • @thehennyy 我认为 OP 的问题是 TSample 类中是 private 的。这让我想知道为什么如果 OP 在Sample-class 之外也需要它,它是私有的。
  • @thehennyy 转换为 IList 就可以了。
  • @HimBromBeere 是的,这可能是根本问题。

标签: c# dynamic reflection


【解决方案1】:
  1. 为什么在将 usersOfSample 转换为动态时无法调用 Clear()?

因为

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

它是object {List&lt;T&gt;}

编辑:

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

Jon Hanna's comment 中所述。

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

List&lt;T&gt; 实现了非泛型 IList,只需将其转换为:

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

你没有。如果课程无法访问,那么这样做是有原因的。如果是您自己的代码,请更改对象的可见性,否则不要乱搞外部代码的内部状态,它可能会在任何时候中断,并且会产生意外且难以调试的副作用。

但如果你真的需要它的反射或投射到 IList。

【讨论】:

  • 我要补充一点,dynamic 将对象视为object 的原因是dynamic 将被视为可在调用它的位置访问的最派生类型。如果它是List&lt;T&gt; 并且T 是一种可访问的类型,那么通过dynamic 将起作用,但如果T 不可访问,则允许的最派生类型是object。有一些方法可以说服dynamic 使用的活页夹不这样做,但它们既复杂又脆弱,这里的答案表明它们也是不必要的。另一种方法是通过反射访问Clear
猜你喜欢
  • 2014-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-28
  • 2011-08-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多