C# dynamic type gotcha - c#

I just ran into the strangest thing and I'm a bit mind = blown at the moment...
The following program compiles fine but when you run it you get a RuntimeBinderException when you try to read Value. 'object' does not contain a definition for 'Value'
class Program
{
interface IContainer
{
int Value { get; }
}
class Factory
{
class Empty : IContainer
{
public int Value
{
get { return 0; }
}
}
static IContainer nullObj = new Empty();
public IContainer GetContainer()
{
return nullObj;
}
}
static void Main(string[] args)
{
dynamic factory = new Factory();
dynamic container = factory.GetContainer();
var num0 = container.Value; // WTF!? RuntimeBinderException, really?
}
}
Here's the mind blowing part. Move the nested type Factory+Empty outside of the Factory class, like so:
class Empty : IContainer
{
public int Value
{
get { return 0; }
}
}
class Factory...
And the program runs just fine, anyone care to explain why that is?
EDIT
In my adventure of coding I of course did something I should have thought about first. That's why you see me rambling a bit about the difference between class private and internal. This was because I had set the InternalsVisibleToAttribute which made my test project (which was consuming the bits in this instance) behave the way they did, which was all by design, although alluding me from the start.
Read Eric Lippert's answer for a good explanation of the rest.
What caught me really of guard was that the dynamic binder takes the visibility of the type of the instance in mind. I have a lot of JavaScript experience and as a JavaScript programmer where there really isn't such a thing as public or private, I was completely fooled by the fact that the visibility mattered, I mean after all, I was accessing this member as if it was of the public interface type (I thought dynamic was simply syntactic sugar for reflection) but the dynamic binder cannot make such an assumption unless you give it a hint, using a simple cast.

The fundamental principle of "dynamic" in C# is: at runtime do the type analysis of the expression as though the runtime type had been the compile time type. So let's see what would happen if we actually did that:
dynamic num0 = ((Program.Factory.Empty)container).Value;
That program would fail because Empty is not accessible. dynamic will not allow you to do an analysis that would have been illegal in the first place.
However, the runtime analyzer realizes this and decides to cheat a little. It asks itself "is there a base class of Empty that is accessible?" and the answer is obviously yes. So it decides to fall back to the base class and analyzes:
dynamic num0 = ((System.Object)container).Value;
Which fails because that program would give you an "object doesn't have a member called Value" error. Which is the error you are getting.
The dynamic analysis never says "oh, you must have meant"
dynamic num0 = ((Program.IContainer)container).Value;
because of course if that's what you had meant, that's what you would have written in the first place. Again, the purpose of dynamic is to answer the question what would have happened had the compiler known the runtime type, and casting to an interface doesn't give you the runtime type.
When you move Empty outside then the dynamic runtime analyzer pretends that you wrote:
dynamic num0 = ((Empty)container).Value;
And now Empty is accessible and the cast is legal, so you get the expected result.
UPDATE:
can compile that code into an assembly, reference this assembly and it will work if the Empty type is outside of the class which would make it internal by default
I am unable to reproduce the described behaviour. Let's try a little example:
public class Factory
{
public static Thing Create()
{
return new InternalThing();
}
}
public abstract class Thing {}
internal class InternalThing : Thing
{
public int Value {get; set;}
}
> csc /t:library bar.cs
class P
{
static void Main ()
{
System.Console.WriteLine(((dynamic)(Factory.Create())).Value);
}
}
> csc foo.cs /r:bar.dll
> foo
Unhandled Exception: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:
'Thing' does not contain a definition for 'Value'
And you see how this works: the runtime binder has detected that InternalThing is internal to the foreign assembly, and therefore is inaccessible in foo.exe. So it falls back to the public base type, Thing, which is accessible but does not have the necessary property.
I'm unable to reproduce the behaviour you describe, and if you can reproduce it then you've found a bug. If you have a small repro of the bug I am happy to pass it along to my former colleagues.

I guess, at runtime, container method calls are just resolved in the private Empty class, which makes your code fail. As far as I know, dynamic can not be used to access private members (or public members of private class)
This should (of course) work :
var num0 = ((IContainer)container).Value;
Here, it is class Empty which is private : so you can not manipulate Empty instances outside of the declaring class (factory). That's why your code fails.
If Empty were internal, you would be able to manipulate its instances accross the whole assembly, (well, not really because Factory is private) making all dynamic calls allowed, and your code work.

Related

Why won't the DLR (dynamic) bind to a private type? [duplicate]

I just ran into the strangest thing and I'm a bit mind = blown at the moment...
The following program compiles fine but when you run it you get a RuntimeBinderException when you try to read Value. 'object' does not contain a definition for 'Value'
class Program
{
interface IContainer
{
int Value { get; }
}
class Factory
{
class Empty : IContainer
{
public int Value
{
get { return 0; }
}
}
static IContainer nullObj = new Empty();
public IContainer GetContainer()
{
return nullObj;
}
}
static void Main(string[] args)
{
dynamic factory = new Factory();
dynamic container = factory.GetContainer();
var num0 = container.Value; // WTF!? RuntimeBinderException, really?
}
}
Here's the mind blowing part. Move the nested type Factory+Empty outside of the Factory class, like so:
class Empty : IContainer
{
public int Value
{
get { return 0; }
}
}
class Factory...
And the program runs just fine, anyone care to explain why that is?
EDIT
In my adventure of coding I of course did something I should have thought about first. That's why you see me rambling a bit about the difference between class private and internal. This was because I had set the InternalsVisibleToAttribute which made my test project (which was consuming the bits in this instance) behave the way they did, which was all by design, although alluding me from the start.
Read Eric Lippert's answer for a good explanation of the rest.
What caught me really of guard was that the dynamic binder takes the visibility of the type of the instance in mind. I have a lot of JavaScript experience and as a JavaScript programmer where there really isn't such a thing as public or private, I was completely fooled by the fact that the visibility mattered, I mean after all, I was accessing this member as if it was of the public interface type (I thought dynamic was simply syntactic sugar for reflection) but the dynamic binder cannot make such an assumption unless you give it a hint, using a simple cast.
The fundamental principle of "dynamic" in C# is: at runtime do the type analysis of the expression as though the runtime type had been the compile time type. So let's see what would happen if we actually did that:
dynamic num0 = ((Program.Factory.Empty)container).Value;
That program would fail because Empty is not accessible. dynamic will not allow you to do an analysis that would have been illegal in the first place.
However, the runtime analyzer realizes this and decides to cheat a little. It asks itself "is there a base class of Empty that is accessible?" and the answer is obviously yes. So it decides to fall back to the base class and analyzes:
dynamic num0 = ((System.Object)container).Value;
Which fails because that program would give you an "object doesn't have a member called Value" error. Which is the error you are getting.
The dynamic analysis never says "oh, you must have meant"
dynamic num0 = ((Program.IContainer)container).Value;
because of course if that's what you had meant, that's what you would have written in the first place. Again, the purpose of dynamic is to answer the question what would have happened had the compiler known the runtime type, and casting to an interface doesn't give you the runtime type.
When you move Empty outside then the dynamic runtime analyzer pretends that you wrote:
dynamic num0 = ((Empty)container).Value;
And now Empty is accessible and the cast is legal, so you get the expected result.
UPDATE:
can compile that code into an assembly, reference this assembly and it will work if the Empty type is outside of the class which would make it internal by default
I am unable to reproduce the described behaviour. Let's try a little example:
public class Factory
{
public static Thing Create()
{
return new InternalThing();
}
}
public abstract class Thing {}
internal class InternalThing : Thing
{
public int Value {get; set;}
}
> csc /t:library bar.cs
class P
{
static void Main ()
{
System.Console.WriteLine(((dynamic)(Factory.Create())).Value);
}
}
> csc foo.cs /r:bar.dll
> foo
Unhandled Exception: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:
'Thing' does not contain a definition for 'Value'
And you see how this works: the runtime binder has detected that InternalThing is internal to the foreign assembly, and therefore is inaccessible in foo.exe. So it falls back to the public base type, Thing, which is accessible but does not have the necessary property.
I'm unable to reproduce the behaviour you describe, and if you can reproduce it then you've found a bug. If you have a small repro of the bug I am happy to pass it along to my former colleagues.
I guess, at runtime, container method calls are just resolved in the private Empty class, which makes your code fail. As far as I know, dynamic can not be used to access private members (or public members of private class)
This should (of course) work :
var num0 = ((IContainer)container).Value;
Here, it is class Empty which is private : so you can not manipulate Empty instances outside of the declaring class (factory). That's why your code fails.
If Empty were internal, you would be able to manipulate its instances accross the whole assembly, (well, not really because Factory is private) making all dynamic calls allowed, and your code work.

Why am I getting a marshal_by_reference warning [duplicate]

Accessing a member on Form may cause a runtime exception because it
is a field of a marshal-by-reference class
I know what this warning is and know how to solve it.
My question is why could this cause a runtime error?
You are probably talking about warning CS1690, repro code:
public class Remotable : MarshalByRefObject {
public int field;
}
public class Test {
public static void Run() {
var obj = new Remotable();
// Warning CS1690:
Console.WriteLine(obj.field.ToString());
}
}
In a remoting scenario, the Test.Run method will work with a proxy of the Remotable object. Building a proxy for a property, method or event isn't much of a problem, just a matter of creating a MethodTable that contains the substitutes. Fields are a problem however, there's nothing to 'hook'. For a MBRO, the JIT compiler no longer generates code to access the field directly, it injects a call to a helper method built into the CLR, JIT_GetField32() in this case.
That helper checks if the object is a proxy and uses the remoting plumbing to obtain the remote value if that's the case. Or just accesses the field directly if it isn't. Making the ToString() call however requires the value to be boxed. That's a problem, boxing isolates the value from the proxy. There is no way to ensure that the boxed value is always an accurate copy of the remoted value. Calling JIT_GetField32() again whenever the ToString() method uses the value to format the string isn't possible.
The workaround for CS1690 is simple, beyond wrapping the field with a property, just copy the field value in a local variable. Now it is crystal clear that the code is working with a copy and there is never a surprise so the compiler won't have to emit a warning.
public static void Run() {
var obj = new Remotable();
var value = obj.field;
Console.WriteLine(value.ToString()); // No warning
}
In addition to the suggestion from #hans-passant, I think another useful way to fix this warning is by turning your field into a property.
public class Remotable : MarshalByRefObject {
public int field;
}
could become
public class Remotable : MarshalByRefObject {
public int field { get; set }
}
and you no longer get any warnings! (Hans Passant already has an excelent explanation for this, see his post)
Obviously, you can not always alter the object you are working with (example: WinForms where the fields are generated for you) so you might have to fallback to using a temporary variable.
Or you can write:
var obj = new Remotable();
Console.WriteLine(((int) obj.field).ToString()); // No warning
Here you take your own responsibility for that cast (unboxing).
If the other side of the marshalled object has died, it will throw a runtime error stating that the referenced object does not exist anymore.

StackOverflowException when accessing member of generic type via dynamic: .NET/C# framework bug?

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.
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");
}
}
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> { }
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.
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?
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>> { }
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<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.)
The problem is that you are deriving a type from itself:
abstract class SetTreeNode<TKey> : KeyTreeNode<SetTreeNode<TKey>, TKey> { }
The type SetTreeNote<TKey> becomes KeyTreeNode<SetTreeNode<TKey>,TKey> which becomes KeyTreeNode<KeyTreeNode<SetTreeNode<TKey>,TKey>,TKey> and this goes on and on until the stack overflows.
I don't know what you are trying to accomplish by using this complex model, but that is your problem.
I managed to reduce it to this example which fails:
interface ISortedSet<TKey> { }
sealed class SetTree<TKey> : BalancedTree<SetTreeNode<TKey>>, ISortedSet<TKey> { }
abstract class BalancedTree<TNode> { }
abstract class SetTreeNode<TKey> : KeyTreeNode<SetTreeNode<TKey>, TKey> { }
abstract class KeyTreeNode<TNode, TKey> : TreeNode<TNode> { }
abstract class TreeNode<TNode> { }
And then I fixed it by doing this:
interface ISortedSet<TKey> { }
sealed class SetTree<TKey> : BalancedTree<SetTreeNode<TKey>>, ISortedSet<TKey> { }
abstract class BalancedTree<TNode> { }
abstract class SetTreeNode<TKey> : KeyTreeNode<TKey, TKey> { }
abstract class KeyTreeNode<TNode, TKey> : TreeNode<TNode> { }
abstract class TreeNode<TNode> { }
The only difference between the two is that I replaced KeyTreeNode<SetTreeNode<TKey>, TKey> with KeyTreeNode<TKey, TKey>
Can someone please explain what's going on? Is this a bug in the framework?
Yes.
The issue is in the way that generic types are resolved into their particular concrete uses.
Okay, let's start with some obvious stuff so as to build up to what the compiler is getting wrong. As you know, with something like List<int> the compilers (whether it's the dynamic compiler, or any of the static compilers since C#2 introduced generics) have to take the List<> type and the int type and combine information about both of those to produce the List<int> type.
Now, consider:
public class Base<T, U>
{
}
public class Derived<T> : Base<T, int>
{
}
Derived<long> l = new Derived<long>();
Here you can see that in the same work on the types Derived<T> and long the compiler has to fill three slots:
The T defined on Derived<>, which gets filled with long.
The T defined on Base<,> which gets filled with the T defined on Derived<>, which was filled with long.
The U defined on Base<,> which gets filled with int.
When you consider nested classes, long inheritance chains, generic types derived from other generic types and adding further generic parameters, and so on, you can see that there's a good few different permutations to cover. If you're starting with Derived<long> and have to answer the question "what is the base type of the class?" (which obviously compilers need to consider a lot) then all of this has to be worked out.
The dynamic compiler was based on the pre-Roslyn static compiler, which was based on the compiler before that which was actually written in C++ rather than C# (there is still quite a lot of the dynamic compiler that while it's in C#, smells of C++). The can be considered as being more similar in end point (code that can be executed) than in start point; a bunch of text that has to be parsed for the static compiler to understand what types and operations are involved vs the dynamic compiler starting with already-existing types and operations represented by objects and flags.
One thing they both need to know that is that if a type is mentioned several times, that it's the same type (that's pretty much the most basic definition of what a type means, after all). If we compile new List<int>((int)x) that would obviously not work unless it knew int meant the same thing both times. They also need to avoid chewing up gigs of RAM.
Both problems are solved by a hash-consing or flyweight-like approach. When it goes to construct the object representing a particular type, it first sees if it has already constructed that type, and only constructs a new one if necessary. This also helps a lot of relationships within hierarchies be correctly constructed, though clearly not the particular case in your question.
For most types (all except for a few special cases like pointers, references, arrays, nullables [though there's an exception to that exception], type parameters… okay, there's actually quite a few exceptions) the state is mostly three things:
A symbol representing the type without specific type-parameters (which is the totality of the representation for non-generic types) but which does include type parameters of the generic definition (for Dictionary<int, int> it has the TKey and TValue of Dictionary<TKey, TValue>).
The set of the types that are parameters directly on the type (whether the T of List<T> for the open type, the int of List<int> for the constructed type, or a mix for e.g. Dictionary<T, int> relative to some generic type or method that defines T).
The set of the type parameters that are either directly on the type (as above) or on an outer type it is nested in.
Okay, so far, so good. If it needs to do something with List<int>.Enumerator it first either finds the List<T> symbol in the store, or adds it if new, then finds List<T>.Enumerator symbol in the store, or adds it if new, then finds int in the store (int is preloaded as a very common type) and finally finds the type that combines List<T>.Enumerator with int in the store, or adds it if new. We now have the only List<int>.Enumerator type object.
The problem, which caused your bug, comes in at the end of this last step. Consider what we said above about having to assign types to base types when creating a concrete implementation of a type. The base type of a concrete generic type is a concrete type, potentially itself a concrete generic type, but the information we have here is of the generic type and some type arguments: We do not know what the concrete generic type is.
The method for finding the base type is lazy-loaded, but calls into the symbol that doesn't know the type parameters to use.
The solution used was to temporarily define that symbol's base type in terms of the concrete base type, call the lazy-loading base-type method, and then set it back again.
I don't know why something was lazy-loaded when it was called immediately after creation. At a guess, I'd say it was something that made more sense in terms of the static compilation, and so got ported over that way rather than rewrite the mechanism from scratch (which would be a more risky approach in most regards).
This works pretty well, even with quite complicated hierarchies. However, if there's a hierarchy that is both circular in terms of type parameters and has more than one step before a non-generic type (such as object) is reached (so the fix-up has to recurse on a base type too) then it isn't able to find the type it's in the process of making (remember the bit about storing the objects for types) because it's been temporarily changed to make the fix-up work, and has to make it again. And again, and again, until you hit a StackOverflowException.
From Adam Maras' answer:
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.
It's almost the opposite, in that the problem is proactively setting the base class in such a way as to prevent it realising it already has a type it needs. I think I managed to fix it today though it remains to be seen if someone sees some problem with that fix I missed (a good thing about contributing to the framework is they have a high standard of code reviews, but that of course means I can't be sure a contribution will be accepted until it's in).

How do I explicitly run the static constructor of an unknown type? [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
How do I invoke a static constructor with reflection?
I've got some initialization code in the static constructor of various classes. I can't create instances, nor do I know the types in advance. I would like to ensure the classes are loaded.
I tried this:
fooType.TypeInitializer.Invoke (new object[0]);
But got a MemberAccessException: Type initializer was not callable.
I'm assuming this is because the cctor is private? Is there a way to fix this without changing the architecture?
Edit: I found a workaround using RuntimeHelpers.RunClassConstructor, but this way seems to be barely documented in the MSDN and I'm not sure if it is a hack or a reasonable, prod system like way.
I'm not sure why this works, but as far as I reason (with help from Skeet) if i have a static class
public static class Statics1
{
public static string Value1 { get; set; }
static Statics1()
{
Console.WriteLine("Statics1 cctor");
Value1 = "Initialized 1";
}
}
The code:
Type staticType = typeof (Statics1);
staticType.TypeInitializer.Invoke(null);
or
staticType.TypeInitializer.Invoke(new object[0]);
will throw with an exception, because somehow this resolves to the .ctor, instead of the .cctor of the class.
If I use an explicitly static class, it is treated like an abstract sealed class, so the exception is that an abstract class cannot be instantiated, and if I use a regular class with a static constructor, the exception is that the type initializer is not callable.
But if I use the Invoke overload with two parameters (instance, params), like this:
Type staticType = typeof (Statics1);
staticType.TypeInitializer.Invoke(null, null);
explicitly stating that I am invoking a static method (that's the meaning of the first null - no instance == static), this works and initializes the class.
That said, static constructors are strange beasts. Invoking one in this way will call the static constructor even if it was already executed, i.e., this code:
Console.WriteLine(Statics1.Value1);
Type staticType = typeof (Statics1);
staticType.TypeInitializer.Invoke(null, null);
will call the static constructor twice. So if your cctors have potentially important sideeffects, such as creating files, opening databases, etc, you might want to rethink this approach.
Also, even though I prefer static constructors for reasons of readability, from a performance perspective, field initializers are a bit faster than static constructors
EDIT: explicitly won't work as-is, as poster states can't know the types in advance. Leaving here as might help clarification for future readers ...
If I understand your needs correctly -- in similar circumstances I create a wrapper that references the static class but remains part of the test suite. You can then instantiate the wrapper and have the static initialized on demand. It'd mean you can leave the architecture unchanged, and keep the wrapper as part of the test framework.
public static class MyStatic
{
public static string SomeToolMethod()
{
return "Hello";
}
}
public class MyStaticWrapper // or proxy, technically?
{
public static string SomeToolMethod()
{
return MyStatic.SomeToolMethod();
}
}
fooType.TypeInitializer.Invoke(new MyStaticWrapper()); /// untested, not sure of syntax here

Corner case in using lambdas expression in base constructor

In the Framework we are building we need the following pattern:
public class BaseRenderer
{
Func<string> renderer;
public BaseRenderer(Func<string> renderer)
{
this.renderer = renderer;
}
public string Render()
{
return renderer();
}
}
public class NameRenderer : BaseRenderer
{
public string Name{ get; set; }
public NameRenderer ()
: base(() =>this.Name)
{}
}
As you see, we create a lambda when calling the base constructor.
public class Program
{
public static void Main()
{
Console.WriteLine(new NameRenderer(){Name = "Foo"}.Render());
}
}
Oddly, when trying to actually use the lambda it throws NullReferenceException (Console Application), or some kind of ExecutionEngineExceptionexception (Web app on IIS).
I think the reason is that this pointer is not ready before calling base constructor, so the lambda is unable to capture this.Name at this stage.
Shouldn't it throw an exception in "capture time" instead of "execution time"?
Is this behavior documented?
I can refactor the code in a different way, but I think it worths a comment.
As asgerhallas correctly points out, this should not be legal according to the specification. We accidentally allowed this bogus usage to sneak by the error detector that searches for incorrect usages of "this" before it is legal to do so. I've fixed the bug; the C# 4 compiler correctly flags your program as an error.
Many apologies for the inconvenience; this was my mistake.
The C# specification at 7.5.7 says: "A this-access is permitted only in the block of an instance constructor, an instance method, or an instance accessor."
And even more directly in 10.11.1: "An instance constructor initializer cannot access the instance being created. Therefore it is a compile-time error to reference this in an argument expression of the constructor initializer, as is it a compile-time error for an argument expression to reference any instance member through a simple-name."
Though the instance has been created according to 7.5.10.
Hmm. That's actually pretty strange. I did not see any compile-time error.
I think you are right. The subclass is not yet constructed when the base class constructor is called and therefore accessing members on the subclass gives you a null reference. CLR doesn't have a way to know at compile time if the instance exists or not.
Moving the logic to the constructor body should fix the problem.
The lambda captured the value of "this" and captured null since the object wasn't constructed yet. This strikes me as a compiler bug, it should have generated an error for this. Code like this normally generates a CS0027 (keyword 'this' is not available in the current context) or CS0120 (an object reference is required). I bet that isn't easy to implement.
Anyhoo, the code cannot work. The NameRenderer class needs a constructor with a string argument so it can initialize the base class.
wouldn't : base(()=>this) be legal? You can do : this() so a reference to this seems to be fine, just not properties on it. The fact that : base(()=>this) is no longer legal just broke some partial function application I did during construction. Can be fixed by moving it into the body of the constructor, but there is an order difference: the base class can no longer be passed transparently a partial function application to itself (because the base class constructor gets called before the body of the subclass constructor).

Categories

Resources