我定义了一个派生自BindingList的泛型类,并且有一个嵌套的非泛型类:
class Generic<T> : BindingList<Generic<T>.Inner>
{
public class Inner
{
public object Foo { get; set; }
}
}
当尝试通过动态引用访问StackOverflowException
属性时,mscorlib中出现Value
,如下所示:
dynamic d = new Generic<string>.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)
答案 0 :(得分:2)
我认为问题出在这个地方
Generic<T> :BindingList<Generic<T>.Inner>
请注意,您将声明的类用作父类BindingList中的泛型参数。所以我相信反射最终会得到一个不定式的循环而你得到StackOverflow。
使用时
var d = new Generic<string>.Inner();
编译器只是用Generic.Inner替换它 所以它和
一样Generic<string>.Inner d = new Generic<string>.Inner();
但是当你使用
时dynamic d = new Generic<string>.Inner();
你真的使用反射。反思开始深入挖掘你的课堂结构,它就像......你的班级=&gt; BindingList =&gt; BindingList的通用参数=&gt;你的类(因为它是BindingList的通用参数)=&gt; BindingList =&gt;依此类推,直到获得StackOverflow。
您可以更改为Generic<T> : BindingList<string>
以打破此不定式循环,它可以正常工作!
答案 1 :(得分:1)
非常感谢你的纠正!我调查了这个我会说非常有趣的时刻,发现我是对的。
首先,这不是一个BUG!这就是微软团队如何解决这个问题。我上面写的所有内容都是相信的!
因此,当我说你最终得到一个不定式循环并获得StackOverflow时,但在我看来,你得到它非常快。所以没有任何长时间没有任何访问你的机器,只是看起来它已经死了。我开始深入研究BindingList的结构以及结果。
我创建了
class Example<T> : Level1<Example<T>>
{
public string Name = "111";
}
public class Level1<T>
{
}
并在主
dynamic d = new Example<string>();
var value = d.Name;
它有效!然后我添加了另一个级别
public class Level1<T> : Level2<T>
{
}
public class Level2<T>
{
}
我得到了StackOverflow。我改为
public class Level1<T> : Level2
{
}
public class Level2
{
}
它再次有效!
所以我认为来自微软的那些人刚才说...所以这是最后一级,无法通过并抛出异常。
现在让我们看一下BindingList<T>
public class BindingList<T> : Collection<T>,
IBindingList, IList, ICollection, IEnumerable, ICancelAddNew,
IRaiseItemChangedEvents
注意Collection<T>
查看List<T>
public class List<T> : IList<T>, ICollection<T>,
IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>, IEnumerable<T>,
IEnumerable
只是界面......
因此它适用于List但不适用于BindingList!我的例子证明了这一点!我相信他们是故意阻止不定式循环。