views:

208

answers:

2

Calling an internal constructor with a dynamic argument in C# 4.0b results in the following exception

System.ArgumentNullException: Value cannot be null. Parameter name: constructor

Example code (thanks to Jon Skeet)

public class Test
{
    internal Test(string x)
    {
    }

    static void Main()
    {
        dynamic d = "";
        new Test(d);
    }
}

It seems the runtime does not consider internal constructors when it's trying to pick the right one. This seems to be a bug, so I posted it on Connect: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=472924

It seems they fixed it for the new version.

+1  A: 

Without seeing the code I would suggest that you are passing a non-instantiated class to your constructor. Ensure that they are within scope and have been instantiated e.g. by use of new, before they are passed to your non-dynamic object.

Edit

On seeing your code I would suggest that you use DynamicObject rather than dynamic for your helper costructor and Entity property.

Edit after seeing Jon's answer

I think that the problem is in using the GetEntity() method to generate the dynamic object instance.

I note that Jon creates an instance of MyDynamicObject within the same scope as he uses it.

I assume that you're generating an instance of your object within the GetEntity() method, in which case it is no longer inscope when you come to use it, being classed as a local object.

Using "MyDynamicObject e = entity;" will force the compiler to imlicitly use the MyDynamicObject constructor and map your result to it. Hence address space is already allocated and in scope to be used when passing it to the Helper constructor.

ChrisBD
@Rik - have adjusted my answer after seeing your code. Try using DynamicObject for Entity property rather than dynamic.
ChrisBD
You mean in the helper class? That doesn't make a difference. Or do you have another reason for preferring the static type?
Rik
@Rik - I think that it's down to your dynamic class instance no longer being in scope when you come to use it.
ChrisBD
It's none of this - see my edited answer.
Jon Skeet
+1  A: 

EDIT: Okay, I've now tracked it down a lot further - it's using an internal constructor that causes a problem.

Here's a really short but complete example which demonstrates the problem:

public class Test
{
    internal Test(string x)
    {
    }

    static void Main()
    {
        dynamic d = "";
        new Test(d);
    }
}

I suggest you log this with Connect - then post the URL here and we can vote on it :)

(My guess is that inside the DLR there's a call to GetConstructor without the appropriate BindingFlags.NonPublic, but that's just a guess...)

Jon Skeet
@Rik - if this doesn't work on your system are you certain that you have C# 4.0 installed? As this functionality was only introduced in that version.
ChrisBD
And the .Net 4.0 runtime?
ChrisBD
I'm working on modifying this code to fail the same way as my own. I predict I will answer my own question this way :) And yes, I do have C#4.0 :)
Rik
@Chris: Without C# 4.0 and .NET 4.0, I don't think Rik would have got as far as an execution-time exception :) @Rik: Yup, I suspect you will. That's one of the great things about coming up with a short but complete example - it's good at finding the problem.
Jon Skeet
I got it to break, see the question. However, it seems I cut myself in the fingers more by using inner classes and access modifiers than by using dynamics.
Rik
Right - will look after tea...
Jon Skeet
Produced a much shorter example - no need for custom dynamic objects etc at all.
Jon Skeet
Hmm. That's interesting. So it looks like a bug maybe? Microsoft's response would be worth seeing.
ChrisBD
@ChrisBD: Oh yes, I'm 99.9% sure it's a bug.
Jon Skeet
I posted it on Connect, see the rewritten post.
Rik
I'm going to guess that this will be resolved "works as designed". There are both practical and semantic issues to consider. For instance, would you really want the possibility that method resolution gives a different result in a partial trust environment?
Curt Hagenlocher
@Curt: Other internal or private calls work fine. The call site knows what was accessible at compile time. I would be *very* surprised if this was resolved as "works as designed" personally. Apart from anything else, if it couldn't bind appropriately it shouldn't just throw a NullReferenceException.
Jon Skeet
Hmm... I see I misread the code; It's obviously a bug no matter now internal is supposed to be handled. I can still reproduce with a build from last week, too.
Curt Hagenlocher