2009-10-11

Uproszczona inicjalizacja kolekcji

Przykład:
public void Test()
{
    List ar1 = new List { new Point(3, 4), new Point(5, 6) };
    ar1.ToString();
}
Kod IL:
.method public hidebysig instance void Test() cil managed
{
    .maxstack 4
    .locals init (
        [0] class [mscorlib]System.Collections.Generic.List`1<valuetype [System.Drawing]System.Drawing.Point> ar1,
        [1] class [mscorlib]System.Collections.Generic.List`1<valuetype [System.Drawing]System.Drawing.Point> <>g__initLocal2d5)
    L_0000: newobj instance void [mscorlib]System.Collections.Generic.List`1<valuetype [System.Drawing]System.Drawing.Point>::.ctor()
    L_0005: stloc.1 
    L_0006: ldloc.1 
    L_0007: ldc.i4.3 
    L_0008: ldc.i4.4 
    L_0009: newobj instance void [System.Drawing]System.Drawing.Point::.ctor(int32, int32)
    L_000e: callvirt instance void [mscorlib]System.Collections.Generic.List`1<valuetype [System.Drawing]System.Drawing.Point>::Add(!0)
    L_0013: ldloc.1 
    L_0014: ldc.i4.5 
    L_0015: ldc.i4.6 
    L_0016: newobj instance void [System.Drawing]System.Drawing.Point::.ctor(int32, int32)
    L_001b: callvirt instance void [mscorlib]System.Collections.Generic.List`1<valuetype [System.Drawing]System.Drawing.Point>::Add(!0)
    L_0020: ldloc.1 
    L_0021: stloc.0 
    L_0022: ldloc.0 
    L_0023: callvirt instance string [mscorlib]System.Object::ToString()
    L_0028: pop 
    L_0029: ret 
}
Widzimy, że inicjalizacja odbywa się poprzez wywołanie metody Add obiektu. Cała konstrukcja listy odbywa się poprzez zmienną tymczasową, dzięki czemu proces ten jest atomowy. Zauważmy też że podczas konstrukcji obiektu nie musimy pisać new List(). Jakie warunki musi spełniać klasa, by użycie takiej inicjalizacji było możliwe? Warunki są dwa. Po pierwsze klasa musi implementować interfejs System.Collections.IEnumerable. Po drugie musi zawierać metodę Add(). Czemu samo posiadanie przez klase metody Add() nie wystarczy nie wiem. Skoro już dano takie ograniczenie o wiele rozsądniejsze było by wymaganie implementacji interfejsu ICollection, który wymaga implementacji metody Add(). Przykład własnej klasy, która pozwala nam na skróconą inicjalizację kolekcji:
class TestA : IEnumerable
{
    public void Add(int a)
    {
    }

    public IEnumerator GetEnumerator()
    {
        throw new NotImplementedException();
    }
}

public void Test()
{
    TestA testa = new TestA { 1, 2 };
    testa.ToString();
}
Wariacje na temat typu parametru metody Add() sobie odpuścimy. Wygląda na to, że musi istnieć bezpośrednia konwersja pomiędzy parametrem metody, a składnikiem inicjalizacji. Teraz przyjrzyjmy się bliżej metodzie Add(). Oto przykład dla metody o dwóch parametrach:
class TestB : IEnumerable
{
    public void Add(int a, int b)
    {
    }

    public IEnumerator GetEnumerator()
    {
        throw new NotImplementedException();
    }
}

public void Test()
{
    TestB testb = new TestB { {1, 2}, {2, 3} };
    testb.ToString();
}
Jest o tyle ważne, że podobnie jak listę możemy inicjalizować słownik:
public void Test()
{
    Dictionary dict = new Dictionary() { { Color.Red, "Red" } };
    dict.ToString();
}

Brak komentarzy:

Prześlij komentarz