Artiklar » .NET 3x » Introduktion till C# 3.0

 
 

Introduktion till C# 3.0

Författare: vimpyboy
Datum: den 3 mars 2007
Antal lästa: 7940
Ej stjärnmärkt

Var – Har variant återuppstått?
En nyhet i C# 3.0 är var. Det påminner en del om variant i Visual Basic, samt Object som finns i .NET, med skillnaderna att både variant och object ej är starkt typade, vilket var är.

Hur fungerar då var?

När man använder var för att deklarera en variabel så känner det automatiskt av vilken typ det är och skapar den.

Kod:
var myInt = 4;
var myString = "Hello, World!";
var myArray = new int[] {1, 2, 3};
var myUsers = new Dictionary<int, User>();



Dessa fungerar på exakt samma sätt som:

Kod:
int myInt = 4;
string myString = "Hello, World!";
int[] myArray = new int[] {1, 2, 3};
Dictionary<int, User> myUsers = new Dictionary<int, User>();



Detta visar hur var fungerar i praktiken, men senare kommer jag gå igenom hur man använder dessa på mer kraftfulla sätt. Om man vet vilken typ instansen ska ha, så bör man ändå för enkelhetens skull deklarera som den direkt. Det finns dock vissa krav för att man ska kunna deklarera som var:

* Man måste ge variablen ett värde vid deklareringen (var myInt = 0)
* Man kan ej deklarera som array direkt.
* Värdet får ej vara null.

Exempel på varianter som kommer att ge ett fel vid kompilering:

Kod:
var x; // Inget värde gavs
var y = {1, 2, 3}; // En collection får ej vara startvärde
var z = null; // Variabeln får ej vara null



Anonyma typer
Nu tar jag för givet att du vet hur var fungerar, och ska visa hur man med anonyma metoder kan skapa typer on the fly och som inte finns fysiskt. Tänk dig att du vill hämta uppgifter om en användare och spara i en klass, då är det vanligaste man gör att skapa en klass som tar hand om uppgifterna och som kan se ut i stil med det här:

Kod:
public class User
{
  string userName = "Namn";
  int Age = 20;
}



Sen skapar du helt enkelt en instans av klassen  User som vanligt. Men i och med anonyma typer kan man få denna klass User utan att i själva verket skapa den. Låter det konstigt? Ja, jag antog det, men nu ska jag visa hur det fungerar:

Kod:
var User = new { userName = "Namn", Age = 20 };



Nu börjar det likna något. Det vi har här är en anonym typ som heter User och är en dynamiskt skapad klass med metoderna userName och Age som vi sedan kan använda på samma sätt som klassen ovan. Skillnaden är att vi nu inte ens behövde skapa klassen som tar hand om användarens uppgifter, utan fick den serverad. Klassen som skapades i bakgrunden och som vi inte ”kan se” ser ut i stil med det här:

Kod:
class Anonymous
  {
  private string _userName = "Namn";
  private int _Age = 20;
  public string userName
  {
  get
  {
  return _userName;
  }
  set
  {
  _userName = value;
  }
  }
  
  public int Age
  {
  get
  {
  return _Age;
  }
  set
  {
  _Age = value;
  }
  }
  }



Bygg ut befintliga klasser
Hur ofta har du inte blivit förargad över att en viss metod inte finns med i en klass? Det värsta är även att det ibland kan vara krångligt att bygga ut en klass genom arv (virtual/abstract) eller kanske helt enkelt omöjligt (sealed), men nu finns det en lösning. I C# 3.0 kan du nämligen bygga ut klasser genom extension methods. Det man gör är att man skapar en egen metod genom att använda nyckelordet this innan argumentet (DataTyp minMetod(this DataTyp NamnPåInstans)) och sedan köra det man vill. Ett exempel kan vara om du vill att string ska ha en metod för att skydda din SQL mot injections (genom att skriva ’). Du vill att det ska vara möjligt genom att skriva strSQL.safeSQL(). För att göra det kan man göra så här:

Kod:
public string safeSQL(this string strSQL)
{
  return strSQL.Replace("'", "''");
}



När du sedan vill skydda din SQL-sats räcker det med att skriva:

Kod:
string InjectionSafeSQL = "SELECT * FROM Foo WHERE Bar = '" + userInput.safeSQL() + "'";



Lambda-uttryck
I C# 2.0 introducerades anonyma metoder som låter en köra kod där annars en delegat förväntades. Lambda är en nyhet i C# 3.0 som tar det steget längre. Ett lambda-uttryck skrivs på detta sätt:

Kod:
(lista med parametrar) => funktion alternativt ett uttryck



Om endast en parameter används, så kan man ta borta parenteserna. Exempel på hur det kan se ut:

Kod:
x => x + 1;
x => { return x + 1; };
(int x) => x + 1;
(int x) => { return x + 1; };
(x, y) => { return x + y };
() => Console.WriteLine();



I det första exemplet skickar man in parameter x och adderar det värdet med 1. Nästa exempel visar däremot hur ett värde returneras efter att ha fått värdet x. Det sista exemplet visar hur man kan använda ett lambda-uttryck där ingen parameter har skickats in.

Objektinitialiserare
När man instansierar ett objekt har man tidigare varit tvungen att först skapa instansen med dess parametrar, och sedan efteråt sätta värden på dess egenskaper i stil med detta:

Kod:
Customer cust = new Customer();
cust.Name = "Leif";
cust.Age = 40;



I C# 3.0 introduceras objektinitialiserare som gör det möjligt att sätta värden på ett objekts egenskaper direkt vid instansieringen genom att efteråt, på samma rad, inom { och } sätta värden, avdelade med ett kommatecken på detta sätt:

Kod:
Customer cust = new Customer() { Name = "Leif", Age = 40 };



Det går även att skapa instanser i generic collections:

Kod:
static void Main(string[] args)
{
  List<Customer> cust = new List<Customer> {
  new Customer {
  cust.Name = "Leif",
  Age = 40,
  Roles = {"Administrators", "Members"}
  },
  new Customer {
  cust.Name = "Lisa",
  Age = 32,
  Roles = {"Members"}
  },
  new Customer {
  cust.Name = "Karin",
  Age = 65,
  Roles = {"Members"}
  }
};



Frågeuttryck
Något som jag själv har saknat i tidigare versioner av C# är ett smidigt sätt att skapa SQL-frågor direkt i koden.

Det ser dock lite annorlunda ut mot SQL med skillnaden att man börjar med From och slutar med Select, vilket är tvärtom mot vanlig SQL. Förklaringen jag har fått från en av utvecklarna är att det är mer logiskt på detta sätt, då man först väljer vilken datakälla man har och sedan sorterar ut just det man vill ha för att sedan välja vilka fält man ska ha med. Detta kan användas mot alla olika collections i C# 3.0, vilket gör att man kan skapa egna klasser som innehåller t.ex. olika användare med diverse uppgifter, och sen gör det möjligt att sortera ut just det man vill ha och sedan presentera det. Något jag själv uppskattar väldigt mycket är möjligheten att använda alla funktioner i .NET Framework för att anpassa datan man hämtar. Om man ska fortsätta med Customer-klassen så kan det se ut på liknande sätt när man ska hämta alla personers namn som versaler:

Kod:
string[] Customers = {"Anna", "Anders", "Bertil", "Kurt", "Evelina"};
var expr = from name in Customers select name.ToUpper();



Detta sparar alla namnen i Customers som versaler i expr som automatiskt sätt som en IEnumerable<string>. För att jobba vidare med samma exempel kan vi välja att t.ex. plocka ut enbart de namnen som har fyra bokstäver, och det gör vi genom:

Kod:
IEnumerable<string> expr = from string s in names where s.Length == 4 select s;



Som ni kanske ser så har jag lagt till string i frågan, och det är enbart för enkelhetens skull, det behövs alltså inte. Sen har jag kollat om s.Length är 4. Satsen ovan kan även skrivas på detta sätt:

Kod:
IEnumerable<string> expr = from s in names.Cast<string>() where s.Length == 4 select s;



Eller för att visa hur den kan se ut med lambda så är det så här:

Kod:
IEnumerable<string> expr = names.Cast<string>().where(s => s.Length == 4);



Något som är väldigt användbart i SQL för att koppla ihop två tabeller är join, och självklart finns det med i C# 3.0.

Kod:
IEnumerable<string> expr = from c in Customers
  join object in Orders on c.UserID equals o.UserID into co
  select new { c.Name, o.OrderID };



Eller om man använder lambda:

Kod:
IEnumerable<string> expr = Customers.Join(
  Orders,
  c => c.UserID,
  o => o.UserID,
  (c, o) => new { c.Name, o.OrderID }
);



Ett annat nyckelord är let som gör att man kan spara ett värde i en variabel.

Kod:
IEnumerable<string> expr = from c in Customers
  join object in Orders on c.UserID equals o.UserID into co
  let sum = co.Count()
  select new { c.Name, o.OrderID, sum };



Här sparar vi summan av co i variabeln sum för att sedan hämta ut det. Vill man sortera datan finns det två olika sätt att göra det på, beroende på åt vilket håll man vill sortera (fallande, höjande). De två olika nyckelorden som finns för det är OrderBy (höjande) och OrderByDescending (fallande).

Kod:
IEnumerable<string> expr = from c in Customers
  orderby const.Name
  select new { c.Name };



Det här kommer lista alla kunders namn i namnordning A-Ö. Byter man ut orderby mot orderbydescending så kommer det istället bli Ö-A. Nästa funktion man kan använda är GroupBy som grupperar olika värden för att man sedan ska kunna sortera efter grupperna.

Kod:
string[] names = { "Anna", "Anders", "Bertil", "Kurt", "Evelina", "Maria", "Agda" };

var groups = names.OrderBy(s => s.Length).GroupBy(s => s.Length);

foreach (IGrouping<int, string> group in groups)
{
  Console.WriteLine("Alla namn med {0} bokstäver:", group.Key);
  foreach (string value in group)
  Console.WriteLine("{0}", value);

  Console.WriteLine();
}



Det här kommer lista alla namnen i names, grupperade efter längden och sorterade efter samma kriterier. Det som skrivs ut är detta:

Alla namn med 4 bokstäver:
Anna
Kurt
Agda

Alla namn med 5 bokstäver:
Maria

Alla namn med 6 bokstäver:
Anders
Bertil

Alla namn med 7 bokstäver:
Evelina

 
     

  » Logga in  
 
Användarnamn

Lösenord

 
     

  » Bli medlem  
  Bli medlem på ASPsidan!  
     

     
  Microsoft  
     

  » Partners  
  Comsolvia  
     
  » ANNONS  
  ingen annons än  
     

  » Senast online  
  Endast för inloggade  
  Antal inloggade: 1  
     

Copyright © 2007 www.ASPsidan.se
ingen sponsrar längre ASPsidan med Dedikerad Server
ASPsidan RSS
   
 XHTML / CSS
Det tog 0,0781 sekunder att ladda sidan