通过动态引用访问嵌套类的成员时发生StackOverflowException

我已经定义了一个派生自BindingList的generics类,并且有一个嵌套的非generics类:

class Generic : BindingList<Generic.Inner> { public class Inner { public object Foo { get; set; } } } 

尝试通过动态引用访问Value属性时,mscorlib中发生StackOverflowException ,如下所示:

 dynamic d = new Generic.Inner(); var value = d.Foo; // StackOverflowException var value = d.Bar // StackOverflowException as well, not a // 'RuntimeBinderException' like you would expect when // trying to access a non-existing member 

这是我能够制作的最小的复制品。

从BindingList派生是一个重要的细节,如果我将其更改为List ,程序正确执行。

为什么会这样?

编辑:

这是调用堆栈的顶部:

 [Managed to Native Transition] mscorlib.dll!System.RuntimeTypeHandle.Instantiate(System.Type[] inst) mscorlib.dll!System.RuntimeType.MakeGenericType(System.Type[] instantiation) Microsoft.CSharp.dll!Microsoft.CSharp.RuntimeBinder.Semantics.CType.CalculateAssociatedSystemTypeForAggregate(Microsoft.CSharp.RuntimeBinder.Semantics.AggregateType aggtype) Microsoft.CSharp.dll!Microsoft.CSharp.RuntimeBinder.Semantics.CType.CalculateAssociatedSystemType(Microsoft.CSharp.RuntimeBinder.Semantics.CType src) Microsoft.CSharp.dll!Microsoft.CSharp.RuntimeBinder.Semantics.CType.AssociatedSystemType.get() Microsoft.CSharp.dll!Microsoft.CSharp.RuntimeBinder.Semantics.TypeManager.GetAggregate(Microsoft.CSharp.RuntimeBinder.Semantics.AggregateSymbol agg, Microsoft.CSharp.RuntimeBinder.Semantics.AggregateType atsOuter, Microsoft.CSharp.RuntimeBinder.Semantics.TypeArray typeArgs) Microsoft.CSharp.dll!Microsoft.CSharp.RuntimeBinder.Semantics.TypeManager.GetAggregate(Microsoft.CSharp.RuntimeBinder.Semantics.AggregateSymbol agg, Microsoft.CSharp.RuntimeBinder.Semantics.TypeArray typeArgsAll) Microsoft.CSharp.dll!Microsoft.CSharp.RuntimeBinder.Semantics.TypeManager.GetAggregate(Microsoft.CSharp.RuntimeBinder.Semantics.AggregateSymbol agg, Microsoft.CSharp.RuntimeBinder.Semantics.TypeArray typeArgsAll) Microsoft.CSharp.dll!Microsoft.CSharp.RuntimeBinder.Semantics.TypeManager.SubstTypeCore(Microsoft.CSharp.RuntimeBinder.Semantics.CType type, Microsoft.CSharp.RuntimeBinder.Semantics.SubstContext pctx) Microsoft.CSharp.dll!Microsoft.CSharp.RuntimeBinder.Semantics.TypeManager.SubstTypeArray(Microsoft.CSharp.RuntimeBinder.Semantics.TypeArray taSrc, Microsoft.CSharp.RuntimeBinder.Semantics.SubstContext pctx) 

非常感谢你的纠正! 我调查了这个我会说非常有趣的时刻,发现我是对的。

首先,这不是一个BUG! 这就是微软团队如何解决这个问题。 我上面写的所有内容我都相信是真的!

因此,当我说你最终得到一个不定式循环并获得StackOverflow时,但在我看来,你得到它非常快。 所以没有任何长时间没有任何访问你的机器,只是看起来它已经死了。 我开始深入研究BindingList的结构以及结果。

我建立

 class Example : Level1> { public string Name = "111"; } public class Level1 { } 

在主要的

 dynamic d = new Example(); var value = d.Name; 

它的工作原理! 然后我添加了另一个级别

 public class Level1 : Level2 { } public class Level2 { } 

我得到了StackOverflow。 我换了

 public class Level1 : Level2 { } public class Level2 { } 

它又有效了!

所以我认为来自微软的人刚刚说过……所以这是最后一级,无法通过并抛出exception。

现在让我们看看BindingList

 public class BindingList : Collection, IBindingList, IList, ICollection, IEnumerable, ICancelAddNew, IRaiseItemChangedEvents 

通知Collection

看看List

 public class List : IList, ICollection, IList, ICollection, IReadOnlyList, IReadOnlyCollection, IEnumerable, IEnumerable 

只是接口….

因此它适用于List但不适用于BindingList!我的例子certificate了这一点!我相信他们故意这样做是为了阻止不定式循环。

我认为问题出在这个地方

 Generic :BindingList.Inner> 

请注意,您使用声明的类作为父类BindingList中的generics参数。 所以我相信reflection最终会得到一个不定式的循环而你得到StackOverflow。

当你使用

 var d = new Generic.Inner(); 

编译器只是用Generic.Inner替换它,所以它是一样的

 Generic.Inner d = new Generic.Inner(); 

但是当你使用的时候

 dynamic d = new Generic.Inner(); 

你真的使用reflection。 反思开始深入挖掘你的类结构,它就像…你的class => BindingList => BindingList的generics参数=>你的类(因为它是BindingList的generics参数)=> BindingList =>等等,直到你获取StackOverflow。

您可以更改为Generic : BindingList来打破这个不定式循环,它可以工作!