Tipos de valor
La mayor parte de los lenguajes de programación proporcionan tipos de datos integrados, como enteros y números de punto flotante, que se copian cuando se pasan como argumentos (es decir, los pasa el valor). En .NET Framework se denominan tipos de valor. El motor de tiempo de ejecución admite dos clases de tipos de valor:
Tipos de valor integrados
.NET Framework define tipos de valor integrados, como System.Int32 y System.Boolean, que se corresponden con y son idénticos a tipos de datos primitivos utilizados por los lenguajes de programación.
Tipos de valor definidos por el usuario
El lenguaje le proporcionará formas de definir sus propios tipos de valor, que derivan de System.ValueType. Si desea definir un tipo que represente un valor pequeño, como un número complejo (mediante dos números de punto flotante) puede decidir definirlo como un tipo de valor, porque el tipo de valor se puede pasar eficazmente por valor. Si el tipo que va a definir se pasaría más eficazmente por referencia, entonces debe definirlo como clase.
Los tipos de valor se guardan con la misma eficacia que los tipos primitivos, pero en ellos se puede llamar a métodos, incluidos los métodos virtuales definidos en las clases System.Object y System.ValueType, además de todos los métodos definidos en el propio tipo de valor. Se pueden crear instancias de los tipos de valor, pasarlos como parámetros, guardarlos como variables locales o guardarlos en un campo de otro tipo de valor u objeto. Los tipos de valor no tienen la sobrecarga asociada al almacenamiento de una instancia de una clase y no requieren constructores.
Para cada tipo de valor, el motor de tiempo de ejecución proporciona un tipo al que se ha aplicado la conversión boxing, que es una clase que tiene el mismo estado y comportamiento que el tipo de valor. Algunos lenguajes requieren el uso de sintaxis especial cuando se necesita el tipo al que se haya aplicado la conversión boxing, otros utilizan el tipo automáticamente cuando es necesario. Cuando se define un tipo de valor, se definen los dos tipos: al que se ha aplicado la conversión boxing y al que se ha aplicado la conversión unboxing.
Los tipos de valor pueden tener campos, propiedades y eventos. También pueden tener métodos estáticos y no estáticos. Cuando se les aplica la conversión boxing, heredan los métodos virtuales de System.ValueType y pueden implementar varias interfaces o ninguna.
Los tipos de valor están sellados, lo que quiere decir que de ellos no se puede derivar ningún otro tipo. Sin embargo, se pueden definir métodos virtuales directamente en el tipo de valor, a los que se puede llamar tanto en la forma del tipo al que se ha aplicado la conversión boxing como en la forma al que se ha aplicado la conversión unboxing. Aunque de un tipo de valor no se puede derivar otro tipo, en un tipo de valor se pueden definir métodos virtuales cuando se utiliza un lenguaje en el que es más cómodo trabajar con métodos virtuales que con métodos no virtuales o estáticos.
En el ejemplo siguiente se muestra cómo construir un tipo de valor para números complejos.
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
[C#]
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);
}
}
Los resultados de este programa son los siguientes:
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)
Vea también
Sistema de tipos común | Introducción a la biblioteca de clases de .NET Framework | Clases | System.Object | System.ValueType