Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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]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_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.

like image 308
chrissie1 Avatar asked May 07 '11 17:05

chrissie1


People also ask

When can anonymous types be created in c#?

In C#, you are allowed to create an anonymous type object with a new keyword without its class definition and var is used to hold the reference of the anonymous types. As shown in the below example, anony_object is an anonymous type object which contains three properties that are s_id, s_name, language.

What keyword do you use to declare an anonymous type?

Essentially an anonymous type is a reference type and can be defined using the var keyword. You can have one or more properties in an anonymous type but all of them are read-only.

Why we use anonymous types in c#?

Anonymous types provide a convenient way to encapsulate a set of read-only properties into a single object without having to explicitly define a type first. The type name is generated by the compiler and is not available at the source code level. The type of each property is inferred by the compiler.

How to specify anonymous type c#?

You create an anonymous type using the new operator with an object initializer syntax. The implicitly typed variable- var is used to hold the reference of anonymous types.


1 Answers

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

like image 52
Jon Skeet Avatar answered Nov 15 '22 12:11

Jon Skeet