Statické proměnné jsou per-T

Tomáš Holan       15. 1. 2011       C#       6289 zobrazení

Toto je sice velmi dobře známý fakt, ale protože na něj narážím docela často, myslím si, že si tady zaslouží připomenout.

(Ve skutečnosti úplně naposledy, kdy jsem na něj narazil, bylo při procházení podkladů pro příspěvek úplně jiný, ten bude ale až někdy později.)

Pokud máme statickou proměnnou v generické třídě nejsou hodnoty statické proměnné sdíleny mezi instancemi s jiným generickým argumentem nebo instancemi s jinou kombinaci generických argumentů (v případě, že třída má generických argumentů více):

class Foo<T>
{
    public static int X;
}

class Test
{
    static void Main()
    {
        Console.WriteLine(Foo<int>.X);      //0

        Foo<int>.X = 1;
        Foo<int>.X = 2;
        Foo<bool>.X = 3;

        Console.WriteLine(Foo<int>.X);      //2
        Console.WriteLine(Foo<bool>.X);     //3
    }
}

Pro úplnost ze specifikace jazyka C# je zde relevantní sekce 25.1.4, která nám říká:

A static variable in a generic class declaration is shared amongst all instances of the same closed constructed type (§26.5.2), but is not shared amongst instances of different closed constructed types. These rules apply regardless of whether the type of the static variable involves any type parameters or not.

Důvod je docela jasný, statické proměnné mohou být také typu T:

class Foo<T>
{
    public static T X;
}

class Test
{
    static void Main()
    {
        Foo<int>.X = 1;
        Foo<int>.X = 2;
        Foo<bool>.X = 3; //<--compile-time error "3 cannot be converted to a bool"

        Foo<bool>.X = true;
    }
}

Tohoto se může využít a také často využívá jako tzv. “type dictionary”, protože statická proměnná v generické třídě funguje vlastně jako static Dictionary<Type, “cokoliv”>. Největší výhodou tohoto přístupu je ale asi to, že inicializace nových prvků pro různá T je velice jednoduchá a automaticky splňuje i thread safety podmínky. Následující příklad ukazuje jak “on demand” vytvářet strongly-typed deserializér např. při nějakém přenosu objektů v XML:

internal static class Deserializer<T>
{
    private static readonly Func<XElement, T> deserializer = CreateDeserializer();

    public static T Deserialize(XElement xml)
    {
        return deserializer(xml);
    }

    private static Func<XElement, T> CreateDeserializer()
    {
        //Create and return deserialization function for typeof(T);
    }
}

Stejný “pattern” je použit i na několika místech přímo v .NET Frameworku např. u tříd Comparer<T> a EqualityComparer<T>.

Nakonec ještě co dělat, když tuto vlastnost chceme obejít tj. potřebujeme, aby naše generická třída sdílela stav nějaké proměnné i mezi instancemi s různou kombinací type parametrů? Kromě varianty tuto proměnnou dát do úplně separátní třídy existuje pouze jediná možnost jak to zařídit a sice dát sdílenou proměnnou do negenerické základní třídy naší generické třídy:

class FooBase
{
    public static int Y;
}

class Foo<T> : FooBase
{
    //Generic stuff
}

class Test
{
    static void Main()
    {
        Foo<int>.Y = 1;
        Foo<int>.Y = 2;
        Foo<bool>.Y = 3;

        Console.WriteLine(Foo<int>.Y);  //3
        Console.WriteLine(Foo<bool>.Y); //3
    }
}

 

hodnocení článku

0       Hodnotit mohou jen registrované uživatelé.

 

Nový příspěvek

 

                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.

Nyní zakládáte pod článkem nové diskusní vlákno.
Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

 

  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:  
Heslo:  

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback