Jaunās konstrukcijas vecajā platformā

Šodien sanāca pastrādāt ar veco studiju (2005), kurā ir pieejama tikai 2.0 .Net platforma. Pēc neilgām debatēm ar projekta vadītāju, pierunāju viņus pāriet vismaz uz 2008 studiju atstājot kā pamata izpildes platformu .Net 2.0.

Tomēr ar laiku pie ērtībām pierod un šajā gadījumā ir runa par jaunajām valodas konstrukcijām C# 3.0 versijā. Jaunās iespējas ļoti saīsina kodu un atvieglo darbu. Pieradis pie C# iespējām, nolēmu nedaudz paeksperimentēt.

Šoreiz doma bija izmēģināt jaunās C# iespējas vecajā platformā. Tika apskatītas šādas konstrukcijas:

  • Nenoteiktie tipi (Implicit Variables)
  • Objektu un kolekciju izveides konstrukcija (Object and Collections Initializer)
  • Lambda izteiksmes (Lambda Expressions)
  • Daļēji definētās metodes (Partial Methods)

 

Nenoteiktie tipi

Zemāk ir uzrādīts koda fragments, kas izmanto nenoteiktos datu tipus:

 

private static void UseImplicitVariables()
{
    var z = "sis ir strings";

    Debug.Assert(z.Equals("sis ir strings"));
}

 

Kā redzams no IL, tad ģenerētais kods ir pilnībā izpildāms arī 2.0 platformā:

 

.method private hidebysig static void  UseImplicitVariables() cil managed
{
  // Code size       25 (0x19)
  .maxstack  2
  .locals init ([0] string z)
  IL_0000:  nop
  IL_0001:  ldstr      "sis ir strings"
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  ldstr      "sis ir strings"
  IL_000d:  callvirt   instance bool [mscorlib]System.String::Equals(string)
  IL_0012:  call       void [System]System.Diagnostics.Debug::Assert(bool)
  IL_0017:  nop
  IL_0018:  ret
} // end of method Program::UseImplicitVariables

 

 

Objektu un kolekciju izveides konstrukcija un Lambda izteiksmes

Zemāk ir uzrādīts koda fragments, kas izmanto šo konstrukciju:

 

private static void UseObjectInitializer()
{
    List<Customer> list = new List<Customer>
                              {
                                  new Customer { Id = 1, Name = "vards 1" },
                                  new Customer { Id = 2, Name = "vards 2" }
                              };

    Debug.Assert(list.Count == 2);

    Customer found = list.Find(c => c.Id == 1);

    Debug.Assert(found.Id == 1);

    Customer cc = new Customer { Id = 1, Name = "vards" };
    Debug.Assert(cc.Id == 1);
}

 

Kā redzams no IL, tad ģenerētais kods ir pilnībā izpildāms arī 2.0 platformā:

 

.method private hidebysig static void  UseObjectInitializer() cil managed
{
  // Code size       201 (0xc9)
  .maxstack  4
  .locals init ([0] class [mscorlib]System.Collections.Generic.List`1<class CSharp20Test.Customer> list,
           [1] class CSharp20Test.Customer found,
           [2] class CSharp20Test.Customer cc,
           [3] class [mscorlib]System.Collections.Generic.List`1<class CSharp20Test.Customer> '<>g__initLocal1',
           [4] class CSharp20Test.Customer '<>g__initLocal2',
           [5] class CSharp20Test.Customer '<>g__initLocal3',
           [6] class CSharp20Test.Customer '<>g__initLocal4')
  IL_0000:  nop
  IL_0001:  newobj     instance void class [mscorlib]System.Collections.Generic.List`1<class CSharp20Test.Customer>::.ctor()
  IL_0006:  stloc.3
  IL_0007:  ldloc.3
  IL_0008:  newobj     instance void CSharp20Test.Customer::.ctor()
  IL_000d:  stloc.s    '<>g__initLocal2'
  IL_000f:  ldloc.s    '<>g__initLocal2'
  IL_0011:  ldc.i4.1
  IL_0012:  callvirt   instance void CSharp20Test.Customer::set_Id(int32)
  IL_0017:  nop
  IL_0018:  ldloc.s    '<>g__initLocal2'
  IL_001a:  ldstr      "vards 1"
  IL_001f:  callvirt   instance void CSharp20Test.Customer::set_Name(string)
  IL_0024:  nop
  IL_0025:  ldloc.s    '<>g__initLocal2'
  IL_0027:  callvirt   instance void class [mscorlib]System.Collections.Generic.List`1<class CSharp20Test.Customer>::Add(!0)
  IL_002c:  nop
  ...

 

Kas attiecas uz lambda izteiksmēm, tad tās tiek konvertētas uz predikātu ar delegātu, kas smuki darbojas arī 2.0 platformā:

 

IL_0065:  ldsfld     class [mscorlib]System.Predicate`1<class CSharp20Test.Customer> CSharp20Test.Program::'CS$<>9__CachedAnonymousMethodDelegate6'
IL_006a:  brtrue.s   IL_007f
IL_006c:  ldnull
IL_006d:  ldftn      bool CSharp20Test.Program::'<UseObjectInitializer>b__5'(class CSharp20Test.Customer)
IL_0073:  newobj     instance void class [mscorlib]System.Predicate`1<class CSharp20Test.Customer>::.ctor(object,
                                                                                                          native int)
IL_0078:  stsfld     class [mscorlib]System.Predicate`1<class CSharp20Test.Customer> CSharp20Test.Program::'CS$<>9__CachedAnonymousMethodDelegate6'
IL_007d:  br.s       IL_007f
IL_007f:  ldsfld     class [mscorlib]System.Predicate`1<class CSharp20Test.Customer> CSharp20Test.Program::'CS$<>9__CachedAnonymousMethodDelegate6'
IL_0084:  callvirt   instance !0 class [mscorlib]System.Collections.Generic.List`1<class CSharp20Test.Customer>::Find(class [mscorlib]System.Predicate`1<!0>)
IL_0089:  stloc.1

 

Daļēji definētās metodes

Zemāk ir attēlots koda fragments, kas izmanto dalītās metodes konstrukciju:

 

public partial class Customer
{
    public int Id { get; set; }
    public string Name { get; set; }

    partial void Check();

    public void Save()
    {
        Check();
    }
}
public partial class Customer
{
    partial void Check()
    {
        // do some checking
        Console.Write("       .... Checking client: " + this.Id);
    }
}

 

IL kods arī saprotams, ka izpildīsies arī uz vecākām versijām:

 

.method public hidebysig instance void  Save() cil managed
{
  // Code size       9 (0x9)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  call       instance void CSharp20Test.Customer::Check()
  IL_0007:  nop
  IL_0008:  ret
} // end of method Customer::Save

 

Ja turpretim, metodes ķermenis nebūtu definēts, tad IL kods izradītos pavisam vienkāršs:

 

.method public hidebysig instance void  Save() cil managed
{
  // Code size       2 (0x2)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ret
} // end of method Customer::Save

 

Kāpēc visas šīs konstrukcijas ir pieejamas arī vecajās platformas versijās? Tāpēc, ka neatkarīgi no mērķa .Net platformas, ko var izvēlēties pie projekta īpašībām, kods tiek kompilēts ar 3.5 platformas C# kompilatoru.

Vienīgā konstrukcija, kas neizpildijās ne 3.0, ne arī 2.0 platformas versijās bija paplašinājuma metodes (Extension Methods), jo programma nemaz nekompilējās, jo nepieciešamās klases atrodas System.Core asemblijā, kas ir pieejams tikai 3.5 platformā.

 

Secinājums: izmantojiet jaunās C# valodas iespējas jaunā studijā un izpildiet kodu bez bežām uz serveriem ar 2.0 platformu, jo jaunās konstrukcijas ir tikai kompilācijas laika transformācija.

 

 

Cerams, ka noderēs!

Published Friday, August 29, 2008 12:19 AM by valdis.iljuconoks

Comments

# ydNTZAXYYjYKTCFn

qGAJft I appreciate you sharing this article.Much thanks again. Much obliged.

Thursday, March 22, 2012 7:38 PM by google plus hangouts

Leave a Comment

(obligāts) 
(obligāts) 
(brīvizvēles)
(obligāts)