Why do my anonymous types not work in Clay when using VB.Net but do work in C#
I was trying out clay in VB.Net but found that I could not get everything to work.
Here is Clay
This works in C#
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
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:
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>j__TPar' '<LatinName>i__Field'
.custom instance void [mscorlib]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggerBrowsableState) = ( 01 00 00 00 00 00 00 00 )
And the public method Get_LatinName is this.
VB:
.method public specialname instance !T0 get_LatinName() cil managed { .custom instance void [mscorlib]System.Diagnostics.DebuggerNonUserCodeAttribute::.ctor() = ( 01 00 00 00 ) // Code size 11 (0xb) .maxstack 1 .locals init (!T0 V_0) IL_0000: ldarg.0 IL_0001: ldfld !0 class VB$AnonymousType_0`1::$LatinName IL_0006: stloc.0 IL_0007: br.s IL_0009 IL_0009: ldloc.0 IL_000a: ret } // end of method VB$AnonymousType_0`1::get_LatinName
C#:
.method public hidebysig specialname instance !'j__TPar' get_LatinName() cil managed { // Code size 11 (0xb) .maxstack 1 .locals init (!'j__TPar' V_0) IL_0000: ldarg.0 IL_0001: ldfld !0 class 'f__AnonymousType0`1'j__TPar'>::'i__Field' IL_0006: stloc.0 IL_0007: br.s IL_0009 IL_0009: ldloc.0 IL_000a: ret } // end of method 'f__AnonymousType0`1'::get_LatinName
And these are the main methods:
VB:
.method public static void Main() cil managed { .entrypoint .custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 ) // Code size 90 (0x5a) .maxstack 7 .locals init ([0] object c, [1] object plant, [2] class VB$AnonymousType_0`1 VB$t_ref$S0, [3] object[] VB$t_array$S0) IL_0000: nop IL_0001: newobj instance void [ClaySharp]ClaySharp.ClayFactory::.ctor() IL_0006: stloc.0 IL_0007: ldloc.0 IL_0008: ldnull IL_0009: ldstr "Plant" IL_000e: ldc.i4.1 IL_000f: newarr [mscorlib]System.Object IL_0014: stloc.3 IL_0015: ldloc.3 IL_0016: ldc.i4.0 IL_0017: ldstr "test" IL_001c: newobj instance void class VB$AnonymousType_0`1::.ctor(!0) IL_0021: stelem.ref IL_0022: nop IL_0023: ldloc.3 IL_0024: ldnull IL_0025: ldnull IL_0026: ldnull IL_0027: call object [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.NewLateBinding::LateGet(object, class [mscorlib]System.Type, string, object[], string[], class [mscorlib]System.Type[], bool[]) IL_002c: call object [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::GetObjectValue(object) IL_0031: stloc.1 IL_0032: ldloc.1 IL_0033: ldnull IL_0034: ldstr "LatinName" IL_0039: ldc.i4.0 IL_003a: newarr [mscorlib]System.Object IL_003f: ldnull IL_0040: ldnull IL_0041: ldnull IL_0042: call object [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.NewLateBinding::LateGet(object, class [mscorlib]System.Type, string, object[], string[], class [mscorlib]System.Type[], bool[]) IL_0047: call object [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::GetObjectValue(object) IL_004c: call void [mscorlib]System.Console::WriteLine(object) IL_0051: nop IL_0052: call string [mscorlib]System.Console::ReadLine() IL_0057: pop IL_0058: nop IL_0059: ret } // end of method Module1::Main
C#:
.method private hidebysig static void Main(string[] args) cil managed { .entrypoint // Code size 299 (0x12b) .maxstack 10 .locals init ([0] object c, [1] object plant, [2] class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo[] CS$0$0000) IL_0000: nop IL_0001: newobj instance void [ClaySharp]ClaySharp.ClayFactory::.ctor() IL_0006: stloc.0 IL_0007: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1f__AnonymousType0`1',object>> ConsoleApplication2.Program/'o__SiteContainer0'::'p__Site1' IL_000c: brtrue.s IL_004c IL_000e: ldc.i4.0 IL_000f: ldstr "Plant" IL_0014: ldnull IL_0015: ldtoken ConsoleApplication2.Program IL_001a: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) IL_001f: ldc.i4.2 IL_0020: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo IL_0025: stloc.2 IL_0026: ldloc.2 IL_0027: ldc.i4.0 IL_0028: ldc.i4.0 IL_0029: ldnull IL_002a: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string) IL_002f: stelem.ref IL_0030: ldloc.2 IL_0031: ldc.i4.1 IL_0032: ldc.i4.1 IL_0033: ldnull IL_0034: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string) IL_0039: stelem.ref IL_003a: ldloc.2 IL_003b: call class [System.Core]System.Runtime.CompilerServices.CallSiteBinder [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.Binder::InvokeMember(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, string, class [mscorlib]System.Collections.Generic.IEnumerable`1, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1) IL_0040: call class [System.Core]System.Runtime.CompilerServices.CallSite`1 class [System.Core]System.Runtime.CompilerServices.CallSite`1f__AnonymousType0`1',object>>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder) IL_0045: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1f__AnonymousType0`1',object>> ConsoleApplication2.Program/'o__SiteContainer0'::'p__Site1' IL_004a: br.s IL_004c IL_004c: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1f__AnonymousType0`1',object>> ConsoleApplication2.Program/'o__SiteContainer0'::'p__Site1' IL_0051: ldfld !0 class [System.Core]System.Runtime.CompilerServices.CallSite`1f__AnonymousType0`1',object>>::Target IL_0056: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1f__AnonymousType0`1',object>> ConsoleApplication2.Program/'o__SiteContainer0'::'p__Site1' IL_005b: ldloc.0 IL_005c: ldstr "test" IL_0061: newobj instance void class 'f__AnonymousType0`1'::.ctor(!0) IL_0066: callvirt instance !3 class [mscorlib]System.Func`4f__AnonymousType0`1',object>::Invoke(!0, !1, !2) IL_006b: stloc.1 IL_006c: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1> ConsoleApplication2.Program/'o__SiteContainer0'::'p__Site2' IL_0071: brtrue.s IL_00b6 IL_0073: ldc.i4 0x100 IL_0078: ldstr "WriteLine" IL_007d: ldnull IL_007e: ldtoken ConsoleApplication2.Program IL_0083: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) IL_0088: ldc.i4.2 IL_0089: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo IL_008e: stloc.2 IL_008f: ldloc.2 IL_0090: ldc.i4.0 IL_0091: ldc.i4.s 33 IL_0093: ldnull IL_0094: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string) IL_0099: stelem.ref IL_009a: ldloc.2 IL_009b: ldc.i4.1 IL_009c: ldc.i4.0 IL_009d: ldnull IL_009e: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string) IL_00a3: stelem.ref IL_00a4: ldloc.2 IL_00a5: call class [System.Core]System.Runtime.CompilerServices.CallSiteBinder [Microsoft.CSharp]Mi开发者_运维知识库crosoft.CSharp.RuntimeBinder.Binder::InvokeMember(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, string, class [mscorlib]System.Collections.Generic.IEnumerable`1, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1) IL_00aa: call class [System.Core]System.Runtime.CompilerServices.CallSite`1 class [System.Core]System.Runtime.CompilerServices.CallSite`1>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder) IL_00af: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1> ConsoleApplication2.Program/'o__SiteContainer0'::'p__Site2' IL_00b4: br.s IL_00b6 IL_00b6: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1> ConsoleApplication2.Program/'o__SiteContainer0'::'p__Site2' IL_00bb: ldfld !0 class [System.Core]System.Runtime.CompilerServices.CallSite`1>::Target IL_00c0: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1> ConsoleApplication2.Program/'o__SiteContainer0'::'p__Site2' IL_00c5: ldtoken [mscorlib]System.Console IL_00ca: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) IL_00cf: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1> ConsoleApplication2.Program/'o__SiteContainer0'::'p__Site3' IL_00d4: brtrue.s IL_0109 IL_00d6: ldc.i4.0 IL_00d7: ldstr "LatinName" IL_00dc: ldtoken ConsoleApplication2.Program IL_00e1: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle) IL_00e6: ldc.i4.1 IL_00e7: newarr [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo IL_00ec: stloc.2 IL_00ed: ldloc.2 IL_00ee: ldc.i4.0 IL_00ef: ldc.i4.0 IL_00f0: ldnull IL_00f1: call class [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo::Create(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfoFlags, string) IL_00f6: stelem.ref IL_00f7: ldloc.2 IL_00f8: call class [System.Core]System.Runtime.CompilerServices.CallSiteBinder [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.Binder::GetMember(valuetype [Microsoft.CSharp]Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags, string, class [mscorlib]System.Type, class [mscorlib]System.Collections.Generic.IEnumerable`1) IL_00fd: call class [System.Core]System.Runtime.CompilerServices.CallSite`1 class [System.Core]System.Runtime.CompilerServices.CallSite`1>::Create(class [System.Core]System.Runtime.CompilerServices.CallSiteBinder) IL_0102: stsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1> ConsoleApplication2.Program/'o__SiteContainer0'::'p__Site3' IL_0107: br.s IL_0109 IL_0109: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1> ConsoleApplication2.Program/'o__SiteContainer0'::'p__Site3' IL_010e: ldfld !0 class [System.Core]System.Runtime.CompilerServices.CallSite`1>::Target IL_0113: ldsfld class [System.Core]System.Runtime.CompilerServices.CallSite`1> ConsoleApplication2.Program/'o__SiteContainer0'::'p__Site3' IL_0118: ldloc.1 IL_0119: callvirt instance !2 class [mscorlib]System.Func`3::Invoke(!0, !1) IL_011e: callvirt instance void class [mscorlib]System.Action`3::Invoke(!0, !1, !2) IL_0123: nop IL_0124: call string [mscorlib]System.Console::ReadLine() IL_0129: pop IL_012a: ret } // end of method Program::Main
The C# and VB version are nothing alike. Seems like the C# version does a lot more.
I don't know anything about Clay, but there is one potentially important difference between C# anonymous types and VB ones: C# anonymous types always have read-only properties, whereas by default, VB ones are mutable.
Only the read-only properties are used in equality and hash code generation in VB. These can be specified with the Key
keyword. So to be closer to your C# code, the VB should be:
Dim c As Object = New ClayFactory
Dim plant = c.Plant(New With { Key .LatinName = "test"})
Console.WriteLine(plant.LatinName)
Console.ReadLine()
Give that a try and see whether it helps :)
精彩评论