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 StackOverflowExcep
I created a shorter, more to-the-point SSCCE that illustrates the problem:
class Program
{
static void Main()
{
dynamic obj = new Third();
Print(obj); // causes stack overflow
}
static void Print(object obj) { }
}
class First where T : First { }
class Second : First where T : First { }
class Third : Second> { }
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
)
and
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.
This code example runs correctly:
class Program
{
static void Main()
{
dynamic obj = new Second();
Print(obj);
}
static void Print(object obj) { }
}
internal class First
where T : First { }
internal class Second : First> { }
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.)