Tipos de valor en el sistema de tipos común

Actualización: noviembre 2007

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 en 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 corresponden y son idénticos a los tipos de datos primitivos utilizados por los lenguajes de programación.

  • Tipos de valor definidos por el usuario

    El lenguaje proporcionará formas de definir sus propios tipos de valor, que se derivan de System.ValueType o System.Enum. 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.

Para obtener información específica de las enumeraciones, vea Enumeraciones del sistema de tipos común.

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

Conceptos

Información general de la biblioteca de clases de .NET Framework

Introducción a la biblioteca de clases de .NET Framework en Visual Studio

Enumeraciones del sistema de tipos común

Referencia

Object

ValueType

Otros recursos

Sistema de tipos comunes