开发者

Why do my anonymous types not work in Clay when using VB.Net but do work in C#

开发者 https://www.devze.com 2023-03-03 09:55 出处:网络
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#

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 :)

0

精彩评论

暂无评论...
验证码 换一张
取 消