Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

StackOverflowException when accessing member of nested class via a dynamic reference

I have defined a generic class that derives from BindingList and has a nested non-generic class:

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

A StackOverflowException occurs in mscorlib when attempting to access the Value property via a dynamic reference like so:

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

This is the smallest reproduction i was able to make.

Deriving from BindingList is an important detail, if i change it to a List the program executes correctly.

Why does this happen?

Edit:

This is the top of the call stack:

[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)  
like image 218
error_404 Avatar asked Oct 26 '13 21:10

error_404


1 Answers

I think the problem is in this place

Generic<T> :BindingList<Generic<T>.Inner>

Notice you use the declared class as a generic parameter in the parent class BindingList. So I believe reflection just ends up with an infinitive loop and you get StackOverflow.

When you use

var d = new Generic<string>.Inner();

compiler just replaces it with Generic.Inner so it is the same like

Generic<string>.Inner d = new Generic<string>.Inner();

But when you use

dynamic d = new Generic<string>.Inner();

You really use reflection. Again reflection starts digging deeper in your class structure and it goes like... your class => BindingList = > generic parameter of BindingList => your class(because it's a generic parameter of BindingList) = > BindingList = > and so on until you get StackOverflow.

You can change to Generic<T> : BindingList<string> to break this infinitive loop and it works!

like image 156
Anton Avatar answered Nov 05 '22 03:11

Anton