当访问StackOverflowException通过动态泛型类型的成员:.NET / C#框架的错误? [英] StackOverflowException when accessing member of generic type via dynamic: .NET/C# framework bug?

查看:330
本文介绍了当访问StackOverflowException通过动态泛型类型的成员:.NET / C#框架的错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在一个程序,我使用了动态关键字调用最佳的匹配方法。然而,我发现,该框架以 StackOverflowException 崩溃,在某些情况下。

In a program I'm using the dynamic keyword to invoke the best matching method. However, I have found that the framework crashes with a StackOverflowException under some circumstances.

我试图简化我的code尽可能同时仍然能够重新产生此问题。

I have tried to simplify my code as much as possible while still being able to re-produce this problem.

class Program
{
    static void Main(string[] args)
    {
        var obj = new SetTree<int>();
        var dyn = (dynamic)obj;
        Program.Print(dyn); // throws StackOverflowException!!
        // Note: this works just fine for 'everything else' but my SetTree<T>
    }
    static void Print(object obj)
    {
        Console.WriteLine("object");
    }

    static void Print<TKey>(ISortedSet<TKey> obj)
    {
        Console.WriteLine("set");
    }
}

这计划将一般打印设置,如果newed了实例实现了 ISortedSet&LT; TKEY的&GT; 接口和任何打印对象其他。但是,具有以下声明的 StackOverflowException 被抛出,而不是(在评论上面提到的)。

That program would normally print "set" if the newed up instance implements the ISortedSet<TKey> interface and print "object" for anything else. But, with the following declarations a StackOverflowException is thrown instead (as noted in a comment above).

interface ISortedSet<TKey> { }

sealed class SetTree<TKey> : BalancedTree<SetTreeNode<TKey>>, ISortedSet<TKey> {}

abstract class BalancedTree<TNode> 
    where TNode : TreeNode<TNode> { }

abstract class SetTreeNode<TKey> : KeyTreeNode<SetTreeNode<TKey>, TKey> { }

abstract class KeyTreeNode<TNode, TKey> : TreeNode<TNode>
    where TNode : KeyTreeNode<TNode, TKey> { }

abstract class TreeNode<TNode>
    where TNode : TreeNode<TNode> { }

这是否是一个错误与否是非常不安的是,一个 StackOverflowException 被抛出,因为我们无法抓住它,也pretty的多少无法确定提前一个异常是否被抛出(并因此终止该进程!)。

Whether this is a bug or not it is very troubling that a StackOverflowException is thrown as we are unable to catch it and also pretty much unable to determine in advance whether an exception will be thrown (and thereby terminate the process!).

有人可以解释这是怎么回事?这是在框架中的错误?

Can someone please explain what's going on? Is this a bug in the framework?

在调试并切换到拆卸模式,我看到这样的:

When debugging and switching to "Disassembly mode" I'm seeing this:

注册转储在该位置:

Register dump at that location:

EAX = 02B811B4 EBX = 0641EA5C ECX = 02C3B0EC EDX = 02C3A504 ESI = 02C2564C
EDI = 0641E9AC EIP = 011027B9 ESP = 0641E91C EBP = 0641E9B8 EFL = 00000202

这并没有告诉我,远不止是一个指标,这确实是必须在该框架某种错误的。

That doesn't tell me much more than being an indicator that this indeed must be some kind of bug in the framework.

我已经申请在Microsoft Connect上的bug报告但我想知道这是怎么回事的。是我的类声明不支持以某种方式?

I've filed a bug report on Microsoft Connect but I'm interested in knowing what's going on here. Are my class declarations unsupported in some way?

不知道为什么发生这种情况使我担心其他地方,我们使用的是动态关键字。我不能相信呢?

Not knowing WHY this is happening causes me to worry about other places where we are using the dynamic keyword. Can I not trust that at all?

推荐答案

我创建了一个更短,更给了点 SSCCE 这说明了这个问题:

I created a shorter, more to-the-point SSCCE that illustrates the problem:

class Program
{
    static void Main()
    {
        dynamic obj = new Third<int>();
        Print(obj); // causes stack overflow
    }

    static void Print(object obj) { }
}

class First<T> where T : First<T> { }

class Second<T> : First<T> where T : First<T> { }

class Third<T> : Second<Third<T>> { }

综观调用栈,它似乎是对反弹在C#运行时绑定两个符号之间:

Looking at the call stack, it seems to be bouncing between two pairs of symbols in the C# runtime binder:

Microsoft.CSharp.RuntimeBinder.SymbolTable.LoadSymbolsFromType(
    System.Type originalType
)

Microsoft.CSharp.RuntimeBinder.SymbolTable.GetConstructedType(
    System.Type type,
    Microsoft.CSharp.RuntimeBinder.Semantics.AggregateSymbol agg
)

Microsoft.CSharp.RuntimeBinder.Semantics.TypeManager.SubstTypeCore(
    Microsoft.CSharp.RuntimeBinder.Semantics.CType type, 
    Microsoft.CSharp.RuntimeBinder.Semantics.SubstContext pctx
)

Microsoft.CSharp.RuntimeBinder.Semantics.TypeManager.SubstTypeArray(
    Microsoft.CSharp.RuntimeBinder.Semantics.TypeArray taSrc,
    Microsoft.CSharp.RuntimeBinder.Semantics.SubstContext pctx
)

如果我不得不大胆的猜测,一些泛型类型的限制嵌套你有事情已经成功地粘合剂混淆成递归遍历参与约束与约束自己的类型。

If I had to hazard a guess, some of the generic type constraint nesting you've got going on has managed to confuse the binder into recursively walking the types involved in the constraints along with the constraints themselves.

继续前进,文件在连接错误;如果编译器不能抓到它,运行时粘合剂最好也不要用。

Go ahead and file a bug on Connect; if the compiler doesn't get caught by this, the runtime binder probably shouldn't either.

这code例如正常运行:

This code example runs correctly:

class Program
{
    static void Main()
    {
        dynamic obj = new Second<int>();
        Print(obj);
    }

    static void Print(object obj) { }
}

internal class First<T>
    where T : First<T> { }

internal class Second<T> : First<Second<T>> { }

这使我相信(不运行时绑定的内部的很多知识),它的主动检查递归的约束,但只有一层。随着中介类之间,粘结剂最终没有检测到递归并试图走它,而不是。 (不过,这一切都只是猜测。我想将它添加到您的连接错误作为附加信息,并看看是否有帮助。)

This leads me to believe (without much knowledge of the internals of the runtime binder) that it's proactively checking for recursive constraints, but only one level deep. With an intermediary class in between, the binder ends up not detecting the recursion and tries to walk it instead. (But that's all just an educated guess. I'd add it to your Connect bug as additional information and see if it helps.)

这篇关于当访问StackOverflowException通过动态泛型类型的成员:.NET / C#框架的错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆