WORDS
C# 7: Värdetuplar med ValueTuple
I C# finns klasser och structar, men ibland räcker det med något lite enklare, och där är tuplar en lösning. Redan före C# 7 fanns det tuplar, men dom var osmidiga att använda, och för att komma åt innehållet fick man skriva använda properties med namn Item1
, Item2
och så vidare. Ett annat alternativ som har funnits länge, är anonyma objekt, men dom kan inte skickas in i metoder eller returneras därifrån.
Den nya värdetupeln, ValueTuple
, har i och med C# 7 inbyggt stöd i språket.
Obs: Den ingår inte i standardbiblioteket ännu. För att kunna använda värdetuplar krävs därför Nuget-paketet System.ValueTuple
, men detta krav kan komma att tas bort i framtiden.
Skapa tuplar
Man kan skapa en tupel genom att ange två eller fler värden inom parentes, separerade med kommatecken:
var letters = ("a", "b");
Man kan komma åt värdena genom Item1
och Item2
, precis som med en vanlig tupel. Man kan också namnge fälten.
(string Alpha, string Beta) letters = ("a", "b");
Fälten Alpha
och Beta
existerar bara under kompileringen, och finns t.ex. inte tillgängliga med reflection (undersökning av typinformation medan programmet kör).
Vid tilldelning av en tupel, kan man också ge fälten namn på högersidan:
var letters = (Alpha: "a", Beta: "b");
Om man anger olika namn på vänster- och högersidan, så får man en kompilatorvarning:
(string First, string Second) letters = (Alpha: "a", Beta: "b");
Tuplar är särskilt användbara som returvärden från metoder deklarerade som private
eller internal
. I metoden nedan returneras det minsta och det största värdet i en följd av heltal:
private static (int Min, int Max) Range(IEnumerable<int> numbers)
{
var min = int.MaxValue;
var max = int.MinValue;
foreach (var n in numbers)
{
min = (n < min) ? n : min;
max = (n > max) ? n : max;
}
return (min, max);
}
Den största fördelen är att man slipper skapa en ny klass eller struct bara för det här värdet. En annan fördel är att tack vare att värdetuplar är en del av språket så kan kompilatorn optimera dom bättre.
Dekonstruera tuplar och andra typer
Man kan använda tupeln man får genom att accessa dess fält:
var range = Range(numbers);
// Använd något med `range.Min` och `range.Max`.
Ofta vill man däremot lagra undan värdena i egna variabler. Detta kallas för att dekonstruera tupeln:
(int min, int max) = Range(numbers);
Man också kan låta kompilatorn sluta sig till vilken datatyp som ska användas:
var (min, max) = Range(numbers);
Är man bara intresserad av något av värdena, kan man elidera alla övriga med _
:
var (_, max) = Range(numbers);
Man kan implementera dekonstruktion för sina egna typer genom att skapa en metod med namnet Deconstruct
:
public class Point
{
public Point(double x, double y)
{
this.X = x;
this.Y = y;
}
public double X { get; }
public double Y { get; }
public void Deconstruct(out double x, out double y)
{
x = this.X;
y = this.Y;
}
}
Denna kan nu användas:
var point = new Point { X = 5.4, Y = 9.6 };
var (x, y) = point;