Introduction

Yesterday I made a post about using Clay with VB.Net. Clay works but not all functionality we have in C# work in VB.Net, which is mildly frustrating. To see if I could find a solution I posted a question on StackOverflow. But no solution yet.

The problem

This works in C#

text dynamic c = new ClayFactory(); var plant = c.Plant(new {LatinName = "test"}); Console.WriteLine(plant.LatinName); Console.ReadLine(); but this does not work in VB.Net

vbnet Dim c As Object = New ClayFactory Dim plant = c.Plant(New With {.LatinName = "test"}) Console.WriteLine(plant.LatinName) Console.ReadLine() I get this error message in VB.Net:

Cannot close over byref parameter

‘$arg1’ referenced in lambda ”

I’m not 100% sure how to solve this if I can even solve it. I’m guessing the VB.Net implementation of anonymous types is slightly different.

I get the error on this line:

vbnet Dim plant = c.Plant(New With {.LatinName = "test"}) I would appreciate if someone could explain this to me.

The IL seems to be quit different.

For VB the private field Latinname is this:

.field private initonly !T0 $LatinName

For C# it is:

.field private initonly !’<latinname>jTPar’ ‘<latinname>iField’<br /> .custom instance void [mscorlib]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 ) </latinname></latinname>

And the public method Get_LatinName is this.

VB:

ce !T0 get_LatinName() cil managed<br /> {<br /> .custom instance void [mscorlib]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 )<br /> // Code size 11 (0xb)<br /> .maxstack 1<br /> .locals init (!T0 V_0)<br /> IL_0000: ldarg.0<br /> IL_0001: ldfld !0 class VB$AnonymousType_01::$LatinName&lt;br /> IL_0006: stloc.0&lt;br /> IL_0007: br.s IL_0009&lt;br /> IL_0009: ldloc.0&lt;br /> IL_000a: ret&lt;br /> } // end of method VB$AnonymousType_01::get_LatinName

C#:

<code class="codespan">.method public hidebysig specialname instance !'j__TPar'&lt;br />
    get_LatinName() cil managed&lt;br />

{<br /> // Code size 11 (0xb)<br /> .maxstack 1<br /> .locals init (!‘jTPar’ V_0)<br /> IL_0000: ldarg.0<br /> IL_0001: ldfld !0 class ‘fAnonymousType01'j__TPar'&gt;::'i__Field'&lt;br /> IL_0006: stloc.0&lt;br /> IL_0007: br.s IL_0009&lt;br /> IL_0009: ldloc.0&lt;br /> IL_000a: ret&lt;br /> } // end of method 'f__AnonymousType01’::get_LatinName

And these are the main methods:

VB:

<code class="codespan">.method public static void  Main() cil managed&lt;br />

{<br /> .entrypoint<br /> .custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 )<br /> // Code size 90 (0x5a)<br /> .maxstack 7<br /> .locals init ([0] object c,<br /> 1 object plant,<br /> 2 class VB$AnonymousType_01 VB$t_ref$S0,&lt;br /> [3] object[] VB$t_array$S0)&lt;br /> IL_0000: nop&lt;br /> IL_0001: newobj instance void [ClaySharp]ClaySharp.ClayFactory::.ctor()&lt;br /> IL_0006: stloc.0&lt;br /> IL_0007: ldloc.0&lt;br /> IL_0008: ldnull&lt;br /> IL_0009: ldstr "Plant"&lt;br /> IL_000e: ldc.i4.1&lt;br /> IL_000f: newarr [mscorlib]System.Object&lt;br /> IL_0014: stloc.3&lt;br /> IL_0015: ldloc.3&lt;br /> IL_0016: ldc.i4.0&lt;br /> IL_0017: ldstr "test"&lt;br /> IL_001c: newobj instance void class VB$AnonymousType_01::.ctor(!0)<br /> IL_0021: stelem.ref<br /> IL_0022: nop<br /> IL_0023: ldloc.3<br /> IL_0024: ldnull<br /> IL_0025: ldnull<br /> IL_0026: ldnull<br /> IL_0027: call object [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.NewLateBinding::LateGet(object,<br /> class [mscorlib]System.Type,<br /> string,<br /> object[],<br /> string[],<br /> class [mscorlib]System.Type[],<br /> bool[])<br /> IL_002c: call object [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::GetObjectValue(object)<br /> IL_0031: stloc.1<br /> IL_0032: ldloc.1<br /> IL_0033: ldnull<br /> IL_0034: ldstr “LatinName”<br /> IL_0039: ldc.i4.0<br /> IL_003a: newarr [mscorlib]System.Object<br /> IL_003f: ldnull<br /> IL_0040: ldnull<br /> IL_0041: ldnull<br /> IL_0042: call object [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.NewLateBinding::LateGet(object,<br /> class [mscorlib]System.Type,<br /> string,<br /> object[],<br /> string[],<br /> class [mscorlib]System.Type[],<br /> bool[])<br /> IL_0047: call object [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::GetObjectValue(object)<br /> IL_004c: call void [mscorlib]System.Console::WriteLine(object)<br /> IL_0051: nop<br /> IL_0052: call string [mscorlib]System.Console::ReadLine()<br /> IL_0057: pop<br /> IL_0058: nop<br /> IL_0059: ret<br /> } // end of method Module1::Main

C#:

<code class="codespan">.method private hidebysig static void  Main(string[] args) cil managed&lt;br />

{<br /> .entrypoint<br /> // Code size 299 (0x12b)<br /> .maxstack 10<br /> .locals init ([0] object c,<br /> 1 object plant,<br /> 2 class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo[] CS$0$0000)<br /> IL_0000: nop<br /> IL_0001: newobj instance void [ClaySharp]ClaySharp.ClayFactory::.ctor()<br /> IL_0006: stloc.0<br /> IL_0007: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite1f__AnonymousType01’,object>> ConsoleApplication2.Program/‘oSiteContainer0’::‘pSite1’<br /> IL_000c: brtrue.s IL_004c<br /> IL_000e: ldc.i4.0<br /> IL_000f: ldstr “Plant”<br /> IL_0014: ldnull<br /> IL_0015: ldtoken ConsoleApplication2.Program<br /> IL_001a: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)<br /> IL_001f: ldc.i4.2<br /> IL_0020: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo<br /> IL_0025: stloc.2<br /> IL_0026: ldloc.2<br /> IL_0027: ldc.i4.0<br /> IL_0028: ldc.i4.0<br /> IL_0029: ldnull<br /> IL_002a: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags,<br /> string)<br /> IL_002f: stelem.ref<br /> IL_0030: ldloc.2<br /> IL_0031: ldc.i4.1<br /> IL_0032: ldc.i4.1<br /> IL_0033: ldnull<br /> IL_0034: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags,<br /> string)<br /> IL_0039: stelem.ref<br /> IL_003a: ldloc.2<br /> IL_003b: call class [System.Core]System.Runtime.CompilerServices.CallSiteBinder [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.Binder::InvokeMember(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags,<br /> string,<br /> class [mscorlib]System.Collections.Generic.IEnumerable1,&lt;br /> class [mscorlib]System.Type,&lt;br /> class [mscorlib]System.Collections.Generic.IEnumerable1)<br /> IL_0040: call class [System.Core]System.Runtime.CompilerServices.CallSite1 class [System.Core]System.Runtime.CompilerServices.CallSite1fAnonymousType01',object&gt;&gt;::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)&lt;br /> IL_0045: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite1fAnonymousType01',object&gt;&gt; ConsoleApplication2.Program/'o__SiteContainer0'::'p__Site1'&lt;br /> IL_004a: br.s IL_004c&lt;br /> IL_004c: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite1fAnonymousType01',object&gt;&gt; ConsoleApplication2.Program/'o__SiteContainer0'::'p__Site1'&lt;br /> IL_0051: ldfld !0 class [System.Core]System.Runtime.CompilerServices.CallSite1fAnonymousType01',object&gt;&gt;::Target&lt;br /> IL_0056: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite1fAnonymousType01',object&gt;&gt; ConsoleApplication2.Program/'o__SiteContainer0'::'p__Site1'&lt;br /> IL_005b: ldloc.0&lt;br /> IL_005c: ldstr "test"&lt;br /> IL_0061: newobj instance void class 'f__AnonymousType01’::.ctor(!0)<br /> IL_0066: callvirt instance !3 class [mscorlib]System.Func4f__AnonymousType01’,object>::Invoke(!0,<br /> !1,<br /> !2)<br /> IL_006b: stloc.1<br /> IL_006c: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite1&gt; ConsoleApplication2.Program/'o__SiteContainer0'::'p__Site2'&lt;br /> IL_0071: brtrue.s IL_00b6&lt;br /> IL_0073: ldc.i4 0x100&lt;br /> IL_0078: ldstr "WriteLine"&lt;br /> IL_007d: ldnull&lt;br /> IL_007e: ldtoken ConsoleApplication2.Program&lt;br /> IL_0083: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)&lt;br /> IL_0088: ldc.i4.2&lt;br /> IL_0089: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo&lt;br /> IL_008e: stloc.2&lt;br /> IL_008f: ldloc.2&lt;br /> IL_0090: ldc.i4.0&lt;br /> IL_0091: ldc.i4.s 33&lt;br /> IL_0093: ldnull&lt;br /> IL_0094: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags,&lt;br /> string)&lt;br /> IL_0099: stelem.ref&lt;br /> IL_009a: ldloc.2&lt;br /> IL_009b: ldc.i4.1&lt;br /> IL_009c: ldc.i4.0&lt;br /> IL_009d: ldnull&lt;br /> IL_009e: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags,&lt;br /> string)&lt;br /> IL_00a3: stelem.ref&lt;br /> IL_00a4: ldloc.2&lt;br /> IL_00a5: call class [System.Core]System.Runtime.CompilerServices.CallSiteBinder [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.Binder::InvokeMember(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags,&lt;br /> string,&lt;br /> class [mscorlib]System.Collections.Generic.IEnumerable1,<br /> class [mscorlib]System.Type,<br /> class [mscorlib]System.Collections.Generic.IEnumerable1)&lt;br /> IL_00aa: call class [System.Core]System.Runtime.CompilerServices.CallSite1 class [System.Core]System.Runtime.CompilerServices.CallSite1&gt;::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)&lt;br /> IL_00af: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite1> ConsoleApplication2.Program/‘oSiteContainer0’::‘pSite2’<br /> IL_00b4: br.s IL_00b6<br /> IL_00b6: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite1&gt; ConsoleApplication2.Program/'o__SiteContainer0'::'p__Site2'&lt;br /> IL_00bb: ldfld !0 class [System.Core]System.Runtime.CompilerServices.CallSite1>::Target<br /> IL_00c0: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite1&gt; ConsoleApplication2.Program/'o__SiteContainer0'::'p__Site2'&lt;br /> IL_00c5: ldtoken [mscorlib]System.Console&lt;br /> IL_00ca: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)&lt;br /> IL_00cf: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite1> ConsoleApplication2.Program/‘oSiteContainer0’::‘pSite3’<br /> IL_00d4: brtrue.s IL_0109<br /> IL_00d6: ldc.i4.0<br /> IL_00d7: ldstr “LatinName”<br /> IL_00dc: ldtoken ConsoleApplication2.Program<br /> IL_00e1: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)<br /> IL_00e6: ldc.i4.1<br /> IL_00e7: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo<br /> IL_00ec: stloc.2<br /> IL_00ed: ldloc.2<br /> IL_00ee: ldc.i4.0<br /> IL_00ef: ldc.i4.0<br /> IL_00f0: ldnull<br /> IL_00f1: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags,<br /> string)<br /> IL_00f6: stelem.ref<br /> IL_00f7: ldloc.2<br /> IL_00f8: call class [System.Core]System.Runtime.CompilerServices.CallSiteBinder [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.Binder::GetMember(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags,<br /> string,<br /> class [mscorlib]System.Type,<br /> class [mscorlib]System.Collections.Generic.IEnumerable1)&lt;br /> IL_00fd: call class [System.Core]System.Runtime.CompilerServices.CallSite1 class [System.Core]System.Runtime.CompilerServices.CallSite1&gt;::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder)&lt;br /> IL_0102: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite1> ConsoleApplication2.Program/‘oSiteContainer0’::‘p__Site3’<br /> IL_0107: br.s IL_0109<br /> IL_0109: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite1&gt; ConsoleApplication2.Program/'o__SiteContainer0'::'p__Site3'&lt;br /> IL_010e: ldfld !0 class [System.Core]System.Runtime.CompilerServices.CallSite1>::Target<br /> IL_0113: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite1&gt; ConsoleApplication2.Program/'o__SiteContainer0'::'p__Site3'&lt;br /> IL_0118: ldloc.1&lt;br /> IL_0119: callvirt instance !2 class [mscorlib]System.Func3::Invoke(!0,<br /> !1)<br /> IL_011e: callvirt instance void class [mscorlib]System.Action`3::Invoke(!0,<br /> !1,<br /> !2)<br /> IL_0123: nop<br /> IL_0124: call string [mscorlib]System.Console::ReadLine()<br /> IL_0129: pop<br /> IL_012a: ret<br /> } // end of method Program::Main

The C# and VB version are nothing alike. Seems like the C# version does a lot more. So there goes the theory C# and VB.Net compile to the same IL.

I also tried debugging Clay to see which line was causing the problem on their side.

The problem is that it is building a whole expressiontree and that it is difficult to say where it actually fails.

```csharp public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args) { Logger.Log(LogLevel.Debug, null, “BindInvokeMember”);

        var argValues = Expression.NewArrayInit(typeof(object), args.Select(x =&gt; Expression.Convert(x.Expression, typeof(Object))));
        var argNames = Expression.Constant(binder.CallInfo.ArgumentNames, typeof(IEnumerable&lt;string&gt;));
        var argNamedEnumerable = Expression.Call(typeof(Arguments).GetMethod("From"), argValues, argNames);

        var binderDefault = binder.FallbackInvokeMember(this, args);

        var missingLambda = Expression.Lambda(Expression.Call(
            GetClayBehavior(),
            IClayBehavior_InvokeMemberMissing,
            Expression.Lambda(binderDefault.Expression),
            GetLimitedSelf(),
            Expression.Constant(binder.Name, typeof(string)),
            argNamedEnumerable));

        var call = Expression.Call(
            GetClayBehavior(),
            IClayBehavior_InvokeMember,
            missingLambda,
            GetLimitedSelf(),
            Expression.Constant(binder.Name, typeof(string)),
            argNamedEnumerable);

        var dynamicSuggestion = new DynamicMetaObject(
            call, BindingRestrictions.GetTypeRestriction(Expression, LimitType).Merge(binderDefault.Restrictions));

        return binder.FallbackInvokeMember(this, args, dynamicSuggestion);
    }```

I think it bombs out on the binder.FallBackInvokeMember. And that just invokes the expressiontree.

But nothing on MSDN seems to suggest this is not compatible with VB.Net or that they have to be carefull about something.

Conclusion

For the moment I am at a lose if you know someone that can help then please do so.