Expresiones de valor predeterminado (Guía de programación de C#)default value expressions (C# programming guide)

Una expresión de valor predeterminado default(T) genera el valor predeterminado de un tipo T.A default value expression default(T) produces the default value of a type T. La siguiente tabla muestra los valores que se generan para distintos tipos:The following table shows which values are produced for various types:

TipoType Valor predeterminadoDefault value
Cualquier tipo de referenciaAny reference type null
Tipo de valor numéricoNumeric value type CeroZero
boolbool false
charchar '\0'
enumenum Valor generado por la expresión (E)0, donde E es el identificador de enumeración.The value produced by the expression (E)0, where E is the enum identifier.
structstruct Valor generado al establecer todos los campos de tipo de valor en sus valores predeterminados y todos los campos de tipo de referencia en null.The value produced by setting all value type fields to their default value and all reference type fields to null.
Tipo que acepta valores NULLNullable type Instancia para la que la propiedad HasValue es false y la propiedad Value no está definida.An instance for which the HasValue property is false and the Value property is undefined.

Las expresiones de valor predeterminado son particularmente útiles en clases y métodos genéricos.Default value expressions are particularly useful in generic classes and methods. Un problema que aparece tras usar elementos genéricos es cómo asignar un valor predeterminado a un T de tipo parametrizado cuando no conoce la información siguiente de antemano:One issue that arises using generics is how to assign a default value of a parameterized type T when you don't know the following in advance:

  • Si T es un tipo de referencia o un tipo de valor.Whether T is a reference type or a value type.
  • Si T es un tipo de valor, si es un valor numérico o un struct.If T is a value type, whether it's a numeric value or a struct.

Dada una variable t de un T de tipo parametrizado, la instrucción t = null solo es válida si T es un tipo de referencia.Given a variable t of a parameterized type T, the statement t = null is only valid if T is a reference type. La asignación t = 0 solo funciona para los tipos de valor numérico, pero no para las estructuras.The assignment t = 0 only works for numeric value types but not for structs. Para resolverlo, use una expresión de valor predeterminado:To solve that, use a default value expression:

T t = default(T);

La expresión default(T) no se limita a métodos y clases genéricas.The default(T) expression is not limited to generic classes and methods. Las expresiones de valor predeterminado pueden usarse con cualquier tipo administrado.Default value expressions can be used with any managed type. Cualquiera de estas expresiones es válida:Any of these expressions are valid:

var s = default(string);
var d = default(dynamic);
var i = default(int);
var n = default(int?); // n is a Nullable int where HasValue is false.

El ejemplo siguiente de la clase GenericList<T> muestra cómo usar el operador default(T) en una clase genérica.The following example from the GenericList<T> class shows how to use the default(T) operator in a generic class. Para obtener más información, vea Introducción a los genéricos.For more information, see Introduction to Generics.

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            // Test with a non-empty list of integers.
            GenericList<int> gll = new GenericList<int>();
            gll.AddNode(5);
            gll.AddNode(4);
            gll.AddNode(3);
            int intVal = gll.GetLast();
            // The following line displays 5.
            System.Console.WriteLine(intVal);

            // Test with an empty list of integers.
            GenericList<int> gll2 = new GenericList<int>();
            intVal = gll2.GetLast();
            // The following line displays 0.
            System.Console.WriteLine(intVal);

            // Test with a non-empty list of strings.
            GenericList<string> gll3 = new GenericList<string>();
            gll3.AddNode("five");
            gll3.AddNode("four");
            string sVal = gll3.GetLast();
            // The following line displays five.
            System.Console.WriteLine(sVal);

            // Test with an empty list of strings.
            GenericList<string> gll4 = new GenericList<string>();
            sVal = gll4.GetLast();
            // The following line displays a blank line.
            System.Console.WriteLine(sVal);
        }
    }

    // T is the type of data stored in a particular instance of GenericList.
    public class GenericList<T>
    {
        private class Node
        {
            // Each node has a reference to the next node in the list.
            public Node Next;
            // Each node holds a value of type T.
            public T Data;
        }

        // The list is initially empty.
        private Node head = null;

        // Add a node at the beginning of the list with t as its data value.
        public void AddNode(T t)
        {
            Node newNode = new Node();
            newNode.Next = head;
            newNode.Data = t;
            head = newNode;
        }

        // The following method returns the data value stored in the last node in
        // the list. If the list is empty, the default value for type T is
        // returned.
        public T GetLast()
        {
            // The value of temp is returned as the value of the method. 
            // The following declaration initializes temp to the appropriate 
            // default value for type T. The default value is returned if the 
            // list is empty.
            T temp = default(T);

            Node current = head;
            while (current != null)
            {
                temp = current.Data;
                current = current.Next;
            }
            return temp;
        }
    }
}

Literal e inferencia de tipo predeterminadosdefault literal and type inference

A partir de C# 7.1, el literal default puede usarse para las expresiones de valor predeterminado cuando el compilador puede deducir el tipo de expresión.Beginning with C# 7.1, the default literal can be used for default value expressions when the compiler can infer the type of the expression. El literal default genera el mismo valor que el equivalente default(T) cuando se deduce el tipo T.The default literal produces the same value as the equivalent default(T) where T is the inferred type. Esto puede simplificar el código disminuyendo la redundancia al declarar un tipo más de una vez.This can make code more concise by reducing the redundancy of declaring a type more than once. El literal default puede usarse en cualquiera de las ubicaciones siguientes:The default literal can be used in any of the following locations:

  • inicializador de variablevariable initializer
  • asignación de variablesvariable assignment
  • Declarar el valor predeterminado de un parámetro opcionaldeclaring the default value for an optional parameter
  • Proporcionar el valor de un argumento de método de llamadaproviding the value for a method call argument
  • Devolver la instrucción (o una expresión de un miembro con cuerpo de expresión)return statement (or expression in an expression bodied member)

El ejemplo siguiente muestra varios usos del literal default en una expresión de valor predeterminado:The following example shows many usages of the default literal in a default value expression:

public struct Point
{
    public double X { get; }
    public double Y { get; }

    public Point(double x, double y)
    {
        X = x;
        Y = y;
    }
}

public class LabeledPoint
{
    public double X { get; private set; }
    public double Y { get; private set; }
    public string Label { get; set; }

    // Providing the value for a default argument:
    public LabeledPoint(double x, double y, string label = default)
    {
        X = x;
        Y = y;
        Label = label;
    }

    public static LabeledPoint MovePoint(LabeledPoint source, 
        double xDistance, double yDistance)
    {
        // return a default value:
        if (source == null)
            return default;

        return new LabeledPoint(source.X + xDistance, source.Y + yDistance, 
        source.Label);
    }

    public static LabeledPoint FindClosestLocation(IEnumerable<LabeledPoint> sequence, 
        Point location)
    {
        // initialize variable:
        LabeledPoint rVal = default;
        double distance = double.MaxValue;

        foreach (var pt in sequence)
        {
            var thisDistance = Math.Sqrt((pt.X - location.X) * (pt.X - location.X) +
                (pt.Y - location.Y) * (pt.Y - location.Y));
            if (thisDistance < distance)
            {
                distance = thisDistance;
                rVal = pt;
            }
        }

        return rVal;
    }

    public static LabeledPoint ClosestToOrigin(IEnumerable<LabeledPoint> sequence)
        // Pass default value of an argument.
        => FindClosestLocation(sequence, default);
}

Vea tambiénSee also