Generics

 

Definition of Generics

By David Bolton, About.com Guide

 

Definition: Generics is a form of abstraction in developing code. Instead of writing a functionor a class for a particular type, it can be written generally to use any type. When an instance of the generic class is instantiated, the type is specified.

Eg. You might create a generic sorting class and when you create an instance of this, the type of entity it sorts is specified. One instance might sort ints, another doubles, and another payroll records.


Lad os kikke på et lille eksempel.

Integer: Vi starter med et helt almindeligt integer eksempel, som er noget vi ofte laver, og dette er ikke generics, men det er nemmere at forstå, om man starter med dette. Integer eksemplet har en klasse Holder som har en global variabel af typen int. I Main laver vi så et objekt af denne type og sætter 5 til int variablen. Siden kan vi udskrive ved kalde på variablen som er public.

Generics.png

Object: Det som vi mangler i integer eksemplet er at kunne indsætte flere typer ind i variablen, som det er nu er der kun integers som kan holdes i den. Men vi kan nemt udvide Holder ved at lave int om til Object. Nu kan vi indsætte alle typer, og classen er blevet meget mere GENEREL. Dette er et tydeligt skridt hen imod Generics, men ikke helt der endnu, fordi vi har nogle problemer med denne her Object refference løsning. Det store problem er at vi må type caste de objekter vi trækker ud af Holder for at kunne bruge dens variabler og metoder. Dette er farligt, fordi kompileren klager ikke, men der er stor sandsynlighed for at systemet går ned i Run Time.

Generic: Det er Type Casting vi kommer af med, ved at lave klassen generic, og den bliver samtidig Type Safe, fordi nu kan kompileren tjekke om koden vil køre i runtime. Den største ændring her er at du i Klasse diffinition skal sige at det er en Generic klasse, det gør vi sådan class Holder <T>. De ekstra <> og T (det behøves ikke at være et T, alle bogstaver kan bruges, de skal bare være koncistente igennem hele klassen) siger til kompileren at nu er det dit ansvar at sørge for at det bliver Type Safe. Nede i klasse er der ingen forskel fra Object eksemplet, andet end at alle Object er nu udskiftet med T. Når vi så skal bruge Holder klasse som generic, skal vi på forhånd sige hvilke typer objekter som Holder variablen SavedValue, det ser sådan ud: Holder<Value> holder. Nu ved kompileren at holder objektet holder Value objekter. Og hvis vi prøver at køre noget andet, som fanger kompileren det, derfor er det Type Safe. Nå vi nu har defineret holder og vi putter Value objekter ind i variablen, så kan vi også hente Value objektet ud af holder og kalde på alt som Value har af public variabler og metoder, altså uden at skulle type cast´e.

Generic: Code

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace Generics3

{

    class Program

    {

        static void Main(string[] args)

        {

            Holder<Value> hold = new Holder<Value>();

            hold.savedValue = new Value();

            hold.savedValue.myName();

        }

        class Holder<T>

        {

            public T savedValue;

        }

 

        class Value

        {

            public void myName()

            {

                Console.WriteLine("I am a Value Class");

            }

        }

    }

}

 

Generics med Interface: Det eksempel vi har ovenover har den mangel at vi ikke kan undersøge eller kalde på de objekter som er gemt inde i Holder, altså de objekter som vi har gemt som T´er. Hvis vi ønsker at Holder skal sortere de data som kommer ind, så kan vi ikke, fordi vi kan ikke kalde metoder på T objekter.
Men det problem kan løses, ved at T´et implimenterer et interface (kontrakt/aftale). Det betyder så at alle de objekter der puttes ind i Holder nu også skal implimentere samme interface. Men så kan der kaldes metoder på T objekterne, og så kan vi sortere eller andet vi måtte have lyst til. Nedenfor er et eksempel som viser hvordan man bruger et Interface sammen med generic.

Generics med Interface

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace GenericWithInterface

{

    class Program

    {

        static void Main(string[] args)

        {

            A<mitObjekt> a = new A<mitObjekt>();

            a.Add(new mitObjekt(5333, "Allan"));

            a.Add(new mitObjekt(1, "Benny"));

            a.Add(new mitObjekt(123, "Conny"));

 

            Console.WriteLine(a.GetBiggest().værdi);

        }

    }

    class A<T> where T : MitInterface

    {

        List<T> minList = new List<T>();

        public void Add(T t)

        {

            minList.Add(t);

        }

        public T GetBiggest()

        {

            T gemmer = minList[0];

            foreach (T t in minList)

            { 

                if (gemmer.sammenlign() < t.sammenlign())

                {

                    gemmer = t;

                }

            }

            return gemmer;

        }

    }

    interface MitInterface

    {

        int sammenlign();

    }

    class mitObjekt : MitInterface

    {

        public int værdi = 0;

        public String navn = "";

        public mitObjekt(int v, String n)

        {

            værdi = v;

            navn = n;

        }

        public int sammenlign()

        {

            return værdi;

        }

    }

}

 


 

Generic Wrapper Class

En meget effektiv måde at lave Generiske klasser er at Wrappe/indkaplse en Datastruktur/Liste og lave sine egne metoder på denne. 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

 

namespace ConsoleApplication3

{

    class Program

    {

        static void Main(string[] args)

        {

            Prioritet<String> p = new Prioritet<string>();

            p.Add("Allan");

            p.Add("Conny");

            p.Add("Bering");

 

            p.PrintAsc();

            Prioritet<int> pint = new Prioritet<int>();

            pint.Add(3);

            pint.Add(1);

            pint.Add(2);

            pint.PrintAsc();

 

            Prioritet<Bil> pBil = new Prioritet<Bil>();

            pBil.Add(new Bil(22));

            pBil.Add(new Bil(24));

            pBil.Add(new Bil(23));

            pBil.PrintAsc();

            Console.WriteLine("Get: " + pBil.get());

            pBil.PrintAsc();

            Console.WriteLine("Get: " + pBil.get());

            pBil.PrintAsc();

            Console.WriteLine("Get: " + pBil.get());

            pBil.PrintAsc();

        }

    }

    class Bil : IComparable

    {

        public int alder = 0;

        public Bil(int a)

        {

            alder = a;

        }

        public int CompareTo(object obj)

        {

            int svar = 0;

            Bil b = (Bil)obj;

            if (alder > b.alder)

            {

                svar = 1;

            }

            else

            {

                svar = -1;

            }

            return svar;

        }

 

        public override string ToString()

        {

            return alder.ToString();

        }

    }

    class Prioritet<T>

    {

        List<T> liste = new List<T>();

 

        public void Add(T t)

        {

            liste.Add(t);

            liste.Sort();

        }

        public void PrintAsc()

        {

            Console.WriteLine("------Sorted Start------------");

            if (liste.Count > 0)

            {

                liste.Reverse();

                foreach (var item in liste)

                {

                    Console.WriteLine(item);

                }

            }

            Console.WriteLine("------------------------------");

        }

        public T get()

        {

            T t = liste[0];

            if (t != null)

            {

                liste.Remove(t);

                liste.Sort();

            }

            else

            {

                t = default(T);

            }

            return t;

        }

    }

}

 

 

 

Fagudtryk

Polymorphism

Arv

Nogle gange ønsker man at kalde en bestemt metode, som kun én af de klasser har som ellers har arvet fra samme sted. Det kan man så gøre ved at spørge hvert enkel objekt hvad type det er, og når man finder den type der søges, så type caster man det, og kan så kalde denne specielle metode.

Polymorphism (C# Programming Guide)

Visual Studio 2012

Polymorphism is often referred to as the third pillar of object-oriented programming, after encapsulation and inheritance. Polymorphism is a Greek word that means "many-shaped" and it has two distinct aspects:

At run time, objects of a derived class may be treated as objects of a base class in places such as method parameters and collections or arrays. When this occurs, the object's declared type is no longer identical to its run-time type.

Base classes may define and implement virtual methods, and derived classes can override them, which means they provide their own definition and implementation. At run-time, when client code calls the method, the CLR looks up the run-time type of the object, and invokes that override of the virtual method. Thus in your source code you can call a method on a base class, and cause a derived class's version of the method to be executed.

Virtual methods enable you to work with groups of related objects in a uniform way.

Generics

Definition: Generics are the most powerful feature of C# 2.0. Generics allow you to define type-safe data structures, without committing to actual data types.

Vi kan gemme vores variabler som objeker i f.eks. en liste, men det kræver at når vi skal bruge disse igen, må vi downcast´e dem. Og i tilfælde af int, String må vi først boxe disse til objekter. Alt dette kan vi være fri for med Generics. Ved at bruge <T> som kaldes type-parameter list, kan kompileren selv lave en ny metode som passer til den type som virkelig er i T. Vi bruger nogle gange en List<T> hvor vi putter vores egne opbjekt typer i. F.eks. List<MitObjekt> minList = new List<MitObjekt>(); Med gernerics kan vi selv lave data strukturer magen til List.