Tipi di valore nel sistema di tipi comuni
Aggiornamento: novembre 2007
La maggioranza dei linguaggi di programmazione fornisce tipi di dati incorporati, come integer e numeri a virgola mobile, che vengono copiati quando sono passati come argomenti, ovvero vengono passati in base al valore. In .NET Framework tali tipi sono detti tipi di valore. In runtime sono supportati due categorie di tipi di valore:
Tipi di valore incorporati
In .NET Framework sono definiti tipi di valore incorporati tipi quali System.Int32 e System.Boolean, che corrispondono e sono identici ai tipi di dati primitivi utilizzati nei linguaggi di programmazione.
Tipi di valore definiti dall'utente
Per ogni linguaggio sono disponibili modalità differenti per la definizione dei tipi di valore personalizzati, derivati da System.ValueType o System.Enum. Per definire un tipo che rappresenta un valore di piccole dimensioni, ad esempio un numero complesso utilizzando due numeri a virgola mobile, è possibile definirlo come tipo di valore, poiché è possibile passare il tipo di valore in modo efficiente per valore. Quando il tipo da definire può essere passato più efficacemente per riferimento deve essere definito come classe.
Per informazioni specifiche sulle enumerazioni, vedere Enumerazioni nel sistema di tipi comuni.
I tipi di valore sono memorizzati in modo tanto efficiente quanto i tipi primitivi, ma è possibile chiamare su di essi vari metodi, compresi i metodi virtuali definiti sulle classi System.Object e System.ValueType e qualsiasi metodo definito direttamente sul tipo di valore. È possibile creare un'istanza dei tipi di valore, passarli come parametri, memorizzarli come variabili locali oppure memorizzarli in un campo di un altro tipo di valore o oggetto. L'overhead dei tipi di valore non è associato alla memorizzazione di un'istanza di una classe e i tipi di valore non richiedono costruttori.
In runtime per ciascun tipo di valore viene fornito un tipo boxed corrispondente, ovvero una classe con lo stesso stato e comportamento del tipo di valore. In alcuni linguaggi è richiesto l'utilizzo di una sintassi particolare per il tipo boxed, mentre in altri questo tipo viene utilizzato automaticamente quando necessario. Quando si definisce un tipo di valore si sta definendo sia il tipo boxed che il tipo unboxed.
Per tipi di valore è possibile specificare campi, proprietà ed eventi, nonché metodi static e non static. Quando i tipi di valore sono boxed, vengono ereditati i metodi virtuali da System.ValueType e possono essere implementate zero o più interfacce.
I tipi di valore sono sealed, ovvero nessun altro tipo può essere derivato da essi. Tuttavia è possibile definire direttamente i metodi virtuali sul tipo di valore e tali metodi possono essere chiamati sulla forma sia boxed che unboxed del tipo. Sebbene non sia possibile derivare un altro tipo da un tipo di valore, è possibile definire i metodi virtuali su un tipo di valore quando si utilizza un linguaggio nel quale è più comodo utilizzare i metodi virtuali anziché quelli non virtuali o statici.
Nell'esempio che segue viene illustrato come costruire un tipo di valore per numeri complessi.
Option Strict
Option Explicit
Imports System
' Value type definition for a complex number representation.
Public Structure Complex
Public r, i As Double
' Constructor.
Public Sub New(r As Double, i As Double)
Me.r = r
Me.i = i
End Sub
' Returns one divided by the current value.
Public ReadOnly Property Reciprocal() As Complex
Get
If r = 0.0 And i = 0.0 Then
Throw New DivideByZeroException()
End If
Dim div As Double = r * r + i * i
Return New Complex(r / div, -i / div)
End Get
End Property
' Conversion methods.
Public Shared Function ToDouble(a As Complex) As Double
Return a.r
End Function
Public Shared Function ToComplex(r As Double) As Complex
Return New Complex(r, 0.0)
End Function
' Basic unary methods.
Public Shared Function ToPositive(a As Complex) As Complex
Return a
End Function
Public Shared Function ToNegative(a As Complex) As Complex
Return New Complex(-a.r, -a.i)
End Function
' Basic binary methods for addition, subtraction, multiplication, and division.
Public Shared Function Add(a As Complex, b As Complex) As Complex
Return New Complex(a.r + b.r, a.i + b.i)
End Function
Public Shared Function Subtract(a As Complex, b As Complex) As Complex
Return New Complex(a.r - b.r, a.i - b.i)
End Function
Public Shared Function Multiply(a As Complex, b As Complex) As Complex
Return New Complex(a.r * b.r - a.i * b.i, a.r * b.i + a.i * b.r)
End Function
Public Shared Function Divide(a As Complex, b As Complex) As Complex
Return Multiply(a, b.Reciprocal)
End Function
' Override the ToString method so the value appears in write statements.
Public Overrides Function ToString As String
Return String.Format("({0}+{1}i)", r, i)
End Function
End Structure
' Entry point.
Public Class ValueTypeSample
Public Shared Sub Main()
Dim a As New Complex(0, 1)
Dim b As New Complex(0, - 2)
Console.WriteLine()
Console.WriteLine("a = " & a.ToString)
Console.WriteLine("b = " & b.ToString)
Console.WriteLine()
Console.WriteLine("a + b = " & Complex.Add(a, b).ToString)
Console.WriteLine("a - b = " & Complex.Subtract(a, b).ToString)
Console.WriteLine("a * b = " & Complex.Multiply(a, b).ToString)
Console.WriteLine("a / b = " & Complex.Divide(a, b).ToString)
Console.WriteLine()
Console.WriteLine("(double)a = " & Complex.ToDouble(a).ToString)
Console.WriteLine("(Complex)5 = " & Complex.ToComplex(5).ToString)
End Sub
End Class
using System;
// Value type definition for a complex number representation.
public struct Complex
{
public double r, i;
// Constructor.
public Complex(double r, double i) { this.r = r; this.i = i; }
// Returns one divided by the current value.
public Complex Reciprocal
{
get
{
if (r == 0d && i == 0d)
throw new DivideByZeroException();
double div = r*r + i*i;
return new Complex(r/div, -i/div);
}
}
// Conversion operators.
public static explicit operator double(Complex a)
{
return a.r;
}
public static implicit operator Complex(double r)
{
return new Complex(r,0d);
}
// Basic unary operators.
public static Complex operator + (Complex a)
{
return a;
}
public static Complex operator - (Complex a)
{
return new Complex(-a.r, -a.i);
}
// Basic binary operators for addition, subtraction, multiplication, and division.
public static Complex operator + (Complex a, Complex b)
{
return new Complex(a.r + b.r, a.i + b.i);
}
public static Complex operator - (Complex a, Complex b)
{
return new Complex(a.r - b.r, a.i - b.i);
}
public static Complex operator * (Complex a, Complex b)
{
return new Complex(a.r*b.r - a.i*b.i, a.r*b.i + a.i*b.r);
}
public static Complex operator / (Complex a, Complex b)
{
return a * b.Reciprocal;
}
// Override the ToString method so the value appears in write statements.
public override string ToString() {
return String.Format("({0}+{1}i)", r, i);
}
}
// Entry point.
public class ValueTypeSample
{
public static void Main()
{
Complex a = new Complex(0, 1);
Complex b = new Complex(0, -2);
Console.WriteLine();
Console.WriteLine("a = " + a);
Console.WriteLine("b = " + b);
Console.WriteLine();
Console.WriteLine("a + b = " + (a+b));
Console.WriteLine("a - b = " + (a-b));
Console.WriteLine("a * b = " + (a*b));
Console.WriteLine("a / b = " + (a/b));
Console.WriteLine();
Console.WriteLine("(double)a = " + (double)a);
Console.WriteLine("(Complex)5 = " + (Complex)5);
}
}
L'output del programma è il seguente:
a = (0+1i)
b = (0+-2i)
a + b = (0+-1i)
a - b = (0+3i)
a * b = (2+0i)
a / b = (-0.5+0i)
(double)a = 0
(Complex)5 = (5+0i)
Vedere anche
Concetti
Cenni preliminari sulla libreria di classi .NET Framework
Introduzione alla libreria di classi .NET Framework in Visual Studio
Enumerazioni nel sistema di tipi comuni