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