MétodosMethods

Un método es un bloque de código que contiene una serie de instrucciones.A method is a code block that contains a series of statements. Un programa hace que se ejecuten las instrucciones al llamar al método y especificando los argumentos de método necesarios.A program causes the statements to be executed by calling the method and specifying any required method arguments. En C#, todas las instrucciones ejecutadas se realizan en el contexto de un método.In C#, every executed instruction is performed in the context of a method. El método Main es el punto de entrada para cada aplicación de C# y se llama mediante Common Language Runtime (CLR) cuando se inicia el programa.The Main method is the entry point for every C# application and it is called by the common language runtime (CLR) when the program is started.

Nota

En este tema se analizan los métodos denominados.This topic discusses named methods. Para obtener información sobre las funciones anónimas, vea Funciones anónimas.For information about anonymous functions, see Anonymous Functions.

Este tema contiene las siguientes secciones:This topic contains the following sections:

Firmas de métodoMethod signatures

Los métodos se declaran en una class o struct al especificar:Methods are declared in a class or struct by specifying:

  • Un nivel de acceso opcional, como, por ejemplo, public o private.An optional access level, such as public or private. De manera predeterminada, es private.The default is private.
  • Modificadores opcionales, como, por ejemplo, abstract o sealed.Optional modifiers such as abstract or sealed.
  • El valor devuelto o, si el método no tiene ninguno, void.The return value, or void if the method has none.
  • El nombre del método.The method name.
  • Los parámetros del método.Any method parameters. Los parámetros de método se encierran entre paréntesis y se separan por comas.Method parameters are enclosed in parentheses and are separated by commas. Los paréntesis vacíos indican que el método no requiere parámetros.Empty parentheses indicate that the method requires no parameters.

Todas estas partes forman la firma del método.These parts together form the method signature.

Nota

Un tipo de valor devuelto de un método no forma parte de la firma del método con el objetivo de sobrecargar el método.A return type of a method is not part of the signature of the method for the purposes of method overloading. Sin embargo, forma parte de la firma del método al determinar la compatibilidad entre un delegado y el método que señala.However, it is part of the signature of the method when determining the compatibility between a delegate and the method that it points to.

En el siguiente ejemplo se define una clase denominada Motorcycle que contiene cinco métodos:The following example defines a class named Motorcycle that contains five methods:

using System;

abstract class Motorcycle
{
   // Anyone can call this.
   public void StartEngine() {/* Method statements here */ }

   // Only derived classes can call this.
   protected void AddGas(int gallons) { /* Method statements here */ }

   // Derived classes can override the base class implementation.
   public virtual int Drive(int miles, int speed) { /* Method statements here */ return 1; }

   // Derived classes can override the base class implementation.
   public virtual int Drive(TimeSpan time, int speed) { /* Method statements here */ return 0; }

   // Derived classes must implement this.
   public abstract double GetTopSpeed(); 
}

Tenga en cuenta que la clase Motorcycle incluye un método sobrecargado, Drive.Note that the Motorcycle class includes an overloaded method, Drive. Dos métodos tienen el mismo nombre, pero se deben diferenciar en sus tipos de parámetros.Two methods have the same name, but must be differentiated by their parameter types.

Invocación del método.Method invocation

Los métodos pueden ser de instancia o estáticos.Methods can be either instance or static. Para invocar un método de instancia es necesario crear una instancia de un objeto y llamar al método del objeto; el método de una instancia actúa en dicha instancia y sus datos.Invoking an instance method requires that you instantiate an object and call the method on that object; an instance method operates on that instance and its data. Si quiere invocar un método estático, haga referencia al nombre del tipo al que pertenece el método; los métodos estáticos no actúan en datos de instancia.You invoke a static method by referencing the name of the type to which the method belongs; static methods do not operate on instance data. Al intentar llamar a un método estático mediante una instancia de objeto se genera un error del compilador.Attempting to call a static method through an object instance generates a compiler error.

Llamar a un método es como acceder a un campo.Calling a method is like accessing a field. Después del nombre de objeto (si se llama a un método de instancia) o el nombre de tipo (si llama a un método static), agregue un punto, el nombre del método y paréntesis.After the object name (if you are calling an instance method) or the type name (if you are calling a static method), add a period, the name of the method, and parentheses. Los argumentos se enumeran entre paréntesis y están separados por comas.Arguments are listed within the parentheses, and are separated by commas.

La definición del método especifica los nombres y tipos de todos los parámetros necesarios.The method definition specifies the names and types of any parameters that are required. Cuando un autor de llamada invoca el método, proporciona valores concretos denominados argumentos para cada parámetro.When a caller invokes the method, it provides concrete values, called arguments, for each parameter. Los argumentos deben ser compatibles con el tipo de parámetro, pero el nombre de argumento, si se usa alguno en el código de llamada, no tiene que ser el mismo que el del parámetro con nombre definido en el método.The arguments must be compatible with the parameter type, but the argument name, if one is used in the calling code, does not have to be the same as the parameter named defined in the method. En el ejemplo siguiente, el método Square incluye un parámetro único de tipo int denominado i.In the following example, the Square method includes a single parameter of type int named i. La primera llamada de método pasa al método Square una variable de tipo int denominada num; la segunda, una constante numérica; y la tercera, una expresión.The first method call passes the Square method a variable of type int named num; the second, a numeric constant; and the third, an expression.

public class Example
{
   public static void Main()
   {
      // Call with an int variable.
      int num = 4;
      int productA = Square(num);

      // Call with an integer literal.
      int productB = Square(12);

      // Call with an expression that evaluates to int.
      int productC = Square(productA * 3);
   }
   
   static int Square(int i)
   {
      // Store input argument in a local variable.
      int input = i;
      return input * input;
   }
}

La forma más común de invocación de método usa argumentos posicionales; proporciona argumentos en el mismo orden que los parámetros de método.The most common form of method invocation used positional arguments; it supplies arguments in the same order as method parameters. Los métodos de la clase Motorcycle se pueden llamar como en el ejemplo siguiente.The methods of the Motorcycle class can therefore be called as in the following example. Por ejemplo, la llamada al método Drive incluye dos argumentos que se corresponden con los dos parámetros de la sintaxis del método.The call to the Drive method, for example, includes two arguments that correspond to the two parameters in the method's syntax. El primero se convierte en el valor del parámetro miles y el segundo en el valor del parámetro speed.The first becomes the value of the miles parameter, the second the value of the speed parameter.

class TestMotorcycle : Motorcycle
{
   public override double GetTopSpeed()
   {
      return 108.4;
   }

   static void Main()
   {
      
      TestMotorcycle moto = new TestMotorcycle();

      moto.StartEngine();
      moto.AddGas(15);
      moto.Drive(5, 20);
      double speed = moto.GetTopSpeed();
      Console.WriteLine("My top speed is {0}", speed);            
   }
}

También se pueden usar argumentos con nombre en lugar de argumentos posicionales al invocar un método.You can also used named arguments instead of positional arguments when invoking a method. Cuando se usan argumentos con nombre, el nombre del parámetro se especifica seguido de dos puntos (":") y el argumento.When using named arguments, you specify the parameter name followed by a colon (":") and the argument. Los argumentos del método pueden aparecer en cualquier orden, siempre que todos los argumentos necesarios están presentes.Arguments to the method can appear in any order, as long as all required arguments are present. En el ejemplo siguiente se usan argumentos con nombre para invocar el método TestMotorcycle.Drive.The following example uses named arguments to invoke the TestMotorcycle.Drive method. En este ejemplo, los argumentos con nombre se pasan en orden inverso desde la lista de parámetros del método.In this example, the named arguments are passed in the opposite order from the method's parameter list.

using System;

class TestMotorcycle : Motorcycle
{
   public override int Drive(int miles, int speed)
   {
      return (int) Math.Round( ((double)miles) / speed, 0);
   }

   public override double GetTopSpeed()
   {
      return 108.4;
   }

   static void Main()
   {
      
      TestMotorcycle moto = new TestMotorcycle();
      moto.StartEngine();
      moto.AddGas(15);
      var travelTime = moto.Drive(speed: 60, miles: 170);
      Console.WriteLine("Travel time: approx. {0} hours", travelTime);            
   }
}
// The example displays the following output:
//      Travel time: approx. 3 hours

Un método se puede invocar con argumentos posicionales y argumentos con nombre.You can invoke a method using both positional arguments and named arguments. Pero un argumento posicional no puede seguir a un argumento con nombre.However, a positional argument cannot follow a named argument. En el ejemplo siguiente se invoca el método TestMotorcycle.Drive del ejemplo anterior con un argumento posicional y un argumento con nombre.The following example invokes the TestMotorcycle.Drive method from the previous example using one positional argument and one named argument.

var travelTime = moto.Drive(170, speed: 55);

Métodos heredados e invalidadosInherited and overridden methods

Además de los miembros que se definen explícitamente en un tipo, un tipo hereda miembros definidos en sus clases base.In addition to the members that are explicitly defined in a type, a type inherits members defined in its base classes. Dado que todos los tipos en el sistema de tipo administrado heredan directa o indirectamente de la clase Object, todos los tipos heredan sus miembros, como Equals(Object), GetType() y ToString().Since all types in the managed type system inherit directly or indirectly from the Object class, all types inherit its members, such as Equals(Object), GetType(), and ToString(). En el ejemplo siguiente se define una clase Person, se crean instancias de dos objetos Person y se llama al método Person.Equals para determinar si los dos objetos son iguales.The following example defines a Person class, instantiates two Person objects, and calls the Person.Equals method to determine whether the two objects are equal. Pero el método Equals no está definido en la clase Person; se hereda de Object.The Equals method, however, is not defined in the Person class; it is inherited from Object.

using System;

public class Person
{
   public String FirstName;
}

public class Example
{
   public static void Main()
   {
      var p1 = new Person();
      p1.FirstName = "John";
      var p2 = new Person();
      p2.FirstName = "John";
      Console.WriteLine("p1 = p2: {0}", p1.Equals(p2));
   }
}
// The example displays the following output:
//      p1 = p2: False

Los tipos pueden invalidar miembros heredados usando la palabra clave override y proporcionando una implementación para el método invalidado.Types can override inherited members by using the override keyword and providing an implementation for the overridden method. La firma del método debe ser igual a la del método invalidado.The method signature must be the same as that of the overridden method. El ejemplo siguiente es similar al anterior, salvo que invalida el método Equals(Object).The following example is like the previous one, except that it overrides the Equals(Object) method. (También invalida el método GetHashCode(), ya que los dos métodos están diseñados para proporcionar resultados coherentes).(It also overrides the GetHashCode() method, since the two methods are intended to provide consistent results.)

using System;

public class Person
{
   public String FirstName;

   public override bool Equals(object obj)
   {
      var p2 = obj as Person; 
      if (p2 == null)
         return false;
      else
         return FirstName.Equals(p2.FirstName);
   }

   public override int GetHashCode()
   {
      return FirstName.GetHashCode();
   } 
}

public class Example
{
   public static void Main()
   {
      var p1 = new Person();
      p1.FirstName = "John";
      var p2 = new Person();
      p2.FirstName = "John";
      Console.WriteLine("p1 = p2: {0}", p1.Equals(p2));
   }
}
// The example displays the following output:
//      p1 = p2: True

Pasar parámetrosPassing parameters

Todos los tipos de C# son tipos de valor o tipos de referencia.Types in C# are either value types or reference types. Para obtener una lista de tipos de valor integrados, vea Types and variables (Tipos y variables).For a list of built-in value types, see Types and variables. De forma predeterminada, los tipos de valor y los tipos de referencia se pasan a un método por valor.By default, both value types and reference types are passed to a method by value.

Pasar parámetros por valorPassing parameters by value

Cuando un tipo de valor se pasa a un método por valor, se pasa una copia del objeto y no el propio objeto.When a value type is passed to a method by value, a copy of the object instead of the object itself is passed to the method. Por lo tanto, los cambios realizados en el objeto en el método llamado no tienen ningún efecto en el objeto original cuando el control vuelve al autor de la llamada.Therefore, changes to the object in the called method have no effect on the original object when control returns to the caller.

En el ejemplo siguiente se pasa un tipo de valor a un método por valor, y el método llamado intenta cambiar el valor del tipo de valor.The following example passes a value type to a method by value, and the called method attempts to change the value type's value. Define una variable de tipo int, que es un tipo de valor, inicializa su valor en 20 y lo pasa a un método denominado ModifyValue que cambia el valor de la variable a 30.It defines a variable of type int, which is a value type, initializes its value to 20, and passes it to a method named ModifyValue that changes the variable's value to 30. Pero cuando el método vuelve, el valor de la variable no cambia.When the method returns, however, the variable's value remains unchanged.

using System;

public class Example
{
   public static void Main()
   {
      int value = 20;
      Console.WriteLine("In Main, value = {0}", value);
      ModifyValue(value);
      Console.WriteLine("Back in Main, value = {0}", value);
   }

   static void ModifyValue(int i)
   {
      i = 30;
      Console.WriteLine("In ModifyValue, parameter value = {0}", i);
      return;
   }
}
// The example displays the following output:
//      In Main, value = 20
//      In ModifyValue, parameter value = 30
//      Back in Main, value = 20

Cuando un objeto de un tipo de referencia se pasa a un método por valor, se pasa por valor una referencia al objeto.When an object of a reference type is passed to a method by value, a reference to the object is passed by value. Es decir, el método no recibe el objeto concreto, sino un argumento que indica la ubicación del objeto.That is, the method receives not the object itself, but an argument that indicates the location of the object. Si cambia un miembro del objeto mediante esta referencia, el cambio se reflejará en el objeto cuando el control vuelva al método de llamada.If you change a member of the object by using this reference, the change is reflected in the object when control returns to the calling method. Pero el reemplazo del objeto pasado al método no tendrá ningún efecto en el objeto original cuando el control vuelva al autor de la llamada.However, replacing the object passed to the method has no effect on the original object when control returns to the caller.

En el ejemplo siguiente se define una clase (que es un tipo de referencia) denominada SampleRefType.The following example defines a class (which is a reference type) named SampleRefType. Crea una instancia de un objeto SampleRefType, asigna 44 a su campo value y pasa el objeto al método ModifyObject.It instantiates a SampleRefType object, assigns 44 to its value field, and passes the object to the ModifyObject method. Fundamentalmente, este ejemplo hace lo mismo que el ejemplo anterior: pasa un argumento por valor a un método.This example does essentially the same thing as the previous example -- it passes an argument by value to a method. Pero, debido a que se usa un tipo de referencia, el resultado es diferente.But because a reference type is used, the result is different. La modificación que se lleva a cabo en ModifyObject para el campo obj.value cambia también el campo value del argumento, rt, en el método Main a 33, tal y como muestra el resultado del ejemplo.The modification that is made in ModifyObject to the obj.value field also changes the value field of the argument, rt, in the Main method to 33, as the output from the example shows.

using System;

public class SampleRefType
{
    public int value;
}

public class Example
{
    public static void Main()
    {
        var rt = new SampleRefType();
        rt.value = 44;
        ModifyObject(rt);
        Console.WriteLine(rt.value);
    }
        
    static void ModifyObject(SampleRefType obj)
    {
        obj.value = 33;
    }
}

Pasar parámetros por referenciaPassing parameters by reference

Pase un parámetro por referencia cuando quiera cambiar el valor de un argumento en un método y reflejar ese cambio cuando el control vuelva al método de llamada.You pass a parameter by reference when you want to change the value of an argument in a method and want to reflect that change when control returns to the calling method. Para pasar un parámetro por referencia, use la palabra clave ref o out.To pass a parameter by reference, you use the ref or out keyword. También puede pasar un valor por referencia para evitar la copia, pero impedir modificaciones igualmente usando la palabra clave in.You can also pass a value by reference to avoid copying but still prevent modifications using the in keyword.

El ejemplo siguiente es idéntico al anterior, salvo que el valor se pasa por referencia al método ModifyValue.The following example is identical to the previous one, except the value is passed by reference to the ModifyValue method. Cuando se modifica el valor del parámetro en el método ModifyValue, el cambio del valor se refleja cuando el control vuelve al autor de la llamada.When the value of the parameter is modified in the ModifyValue method, the change in value is reflected when control returns to the caller.

using System;

public class Example
{
   public static void Main()
   {
      int value = 20;
      Console.WriteLine("In Main, value = {0}", value);
      ModifyValue(ref value);
      Console.WriteLine("Back in Main, value = {0}", value);
   }

   static void ModifyValue(ref int i)
   {
      i = 30;
      Console.WriteLine("In ModifyValue, parameter value = {0}", i);
      return;
   }
}
// The example displays the following output:
//      In Main, value = 20
//      In ModifyValue, parameter value = 30
//      Back in Main, value = 30

Un patrón común que se usa en parámetros ref implica intercambiar los valores de variables.A common pattern that uses by ref parameters involves swapping the values of variables. Se pasan dos variables a un método por referencia y el método intercambia su contenido.You pass two variables to a method by reference, and the method swaps their contents. En el ejemplo siguiente se intercambian valores enteros.The following example swaps integer values.

using System;

public class Example
{
   static void Main()
   {
      int i = 2, j = 3;
      System.Console.WriteLine("i = {0}  j = {1}" , i, j);

      Swap(ref i, ref j);

      System.Console.WriteLine("i = {0}  j = {1}" , i, j);
   }

   static void Swap(ref int x, ref int y)
   {
      int temp = x;
      x = y;
      y = temp;
   }   
}
// The example displays the following output:
//      i = 2  j = 3
//      i = 3  j = 2

Pasar un parámetro de tipo de referencia le permite cambiar el valor de la propia referencia, en lugar del valor de sus campos o elementos individuales.Passing a reference-type parameter allows you to change the value of the reference itself, rather than the value of its individual elements or fields.

Matrices de parámetrosParameter arrays

A veces, el requisito de especificar el número exacto de argumentos al método es restrictivo.Sometimes, the requirement that you specify the exact number of arguments to your method is restrictive. El uso de la palabra clave params para indicar que un parámetro es una matriz de parámetros permite llamar al método con un número variable de argumentos.By using the params keyword to indicate that a parameter is a parameter array, you allow your method to be called with a variable number of arguments. El parámetro etiquetado con la palabra clave params debe ser un tipo de matriz y ser el último parámetro en la lista de parámetros del método.The parameter tagged with the params keyword must be an array type, and it must be the last parameter in the method's parameter list.

Un autor de llamada puede luego invocar el método de una de las tres maneras siguientes:A caller can then invoke the method in either of three ways:

  • Si se pasa una matriz del tipo adecuado que contenga el número de elementos que se quiera.By passing an array of the appropriate type that contains the desired number of elements.
  • Si se pasa una lista separada por comas de los argumentos individuales del tipo adecuado para el método.By passing a comma-separated list of individual arguments of the appropriate type to the method.
  • Si no se proporciona un argumento a la matriz de parámetros.By not providing an argument to the parameter array.

En el ejemplo siguiente se define un método denominado GetVowels que devuelve todas las vocales de una matriz de parámetros.The following example defines a method named GetVowels that returns all the vowels from a parameter array. El método Main muestra las tres formas de invocar el método.The Main method illustrates all three ways of invoking the method. Los autores de llamadas no deben proporcionar argumentos para los parámetros que incluyen el modificador params.Callers are not required to supply any arguments for parameters that include the params modifier. En ese caso, el parámetro es null.In that case, the parameter is null.

using System;
using System.Linq;

class Example
{
    static void Main()
    {
        string fromArray = GetVowels(new[] { "apple", "banana", "pear" });
        Console.WriteLine($"Vowels from array: '{fromArray}'");

        string fromMultipleArguments = GetVowels("apple", "banana", "pear");
        Console.WriteLine($"Vowels from multiple arguments: '{fromMultipleArguments}'");

        string fromNoValue = GetVowels();
        Console.WriteLine($"Vowels from no value: '{fromNoValue}'");
    }

    static string GetVowels(params string[] input)
    {
        if (input == null || input.Length == 0)
        {
            return string.Empty;
        }

        var vowels = new char[] { 'A', 'E', 'I', 'O', 'U' };
        return string.Concat(
            input.SelectMany(
                word => word.Where(letter => vowels.Contains(char.ToUpper(letter)))));
    }
}

// The example displays the following output:
//     Vowels from array: 'aeaaaea'
//     Vowels from multiple arguments: 'aeaaaea'
//     Vowels from no value: ''

Argumentos y parámetros opcionalesOptional parameters and arguments

La definición de un método puede especificar que sus parámetros son necesarios o que son opcionales.A method definition can specify that its parameters are required or that they are optional. Los parámetros son necesarios de forma predeterminada.By default, parameters are required. Para especificar parámetros opcionales se incluye el valor predeterminado del parámetro en la definición del método.Optional parameters are specified by including the parameter's default value in the method definition. Cuando se llama al método, si no se proporciona ningún argumento para un parámetro opcional, se usa el valor predeterminado.When the method is called, if no argument is supplied for an optional parameter, the default value is used instead.

El valor predeterminado del parámetro debe asignarse con uno de los siguientes tipos de expresiones:The parameter's default value must be assigned by one of the following kinds of expressions:

  • Una constante, como una cadena literal o un número.A constant, such as a literal string or number.
  • Una expresión con el formato new ValType, donde ValType es un tipo de valor.An expression of the form new ValType, where ValType is a value type. Tenga en cuenta que esta acción invoca el constructor sin parámetros implícito del tipo de valor, que no es un miembro real del tipo.Note that this invokes the value type's implicit parameterless constructor, which is not an actual member of the type.
  • Una expresión con el formato default(ValType), donde ValType es un tipo de valor.An expression of the form default(ValType), where ValType is a value type.

Si un método incluye parámetros necesarios y opcionales, los parámetros opcionales se definen al final de la lista de parámetros, después de todos los parámetros necesarios.If a method includes both required and optional parameters, optional parameters are defined at the end of the parameter list, after all required parameters.

En el ejemplo siguiente se define un método, ExampleMethod, que tiene un parámetro necesario y dos opcionales.The following example defines a method, ExampleMethod, that has one required and two optional parameters.

using System;

public class Options
{
   public void ExampleMethod(int required, int optionalInt = default(int),
                             string description = "Optional Description")
   {
      Console.WriteLine("{0}: {1} + {2} = {3}", description, required, 
                        optionalInt, required + optionalInt);
   }
}

Si se invoca un método con varios argumentos opcionales mediante argumentos posicionales, el autor de la llamada debe proporcionar un argumento para todos los parámetros opcionales, del primero al último, a los que se proporcione un argumento.If a method with multiple optional arguments is invoked using positional arguments, the caller must supply an argument for all optional parameters from the first one to the last one for which an argument is supplied. Por ejemplo, en el caso del método ExampleMethod, si el autor de la llamada proporciona un argumento para el parámetro description, también debe proporcionar uno para el parámetro optionalInt.In the case of the ExampleMethod method, for example, if the caller supplies an argument for the description parameter, it must also supply one for the optionalInt parameter. opt.ExampleMethod(2, 2, "Addition of 2 and 2"); es una llamada de método válida; opt.ExampleMethod(2, , "Addition of 2 and 0"); genera un error del compilador, "Falta un argumento".opt.ExampleMethod(2, 2, "Addition of 2 and 2"); is a valid method call; opt.ExampleMethod(2, , "Addition of 2 and 0"); generates an "Argument missing" compiler error.

Si se llama a un método mediante argumentos con nombre o una combinación de argumentos posicionales y con nombre, el autor de la llamada puede omitir los argumentos que siguen al último argumento posicional en la llamada al método.If a method is called using named arguments or a combination of positional and named arguments, the caller can omit any arguments that follow the last positional argument in the method call.

En el ejemplo siguiente se llama tres veces al método ExampleMethod.The following example calls the ExampleMethod method three times. Las dos primeras llamadas al método usan argumentos posicionales.The first two method calls use positional arguments. La primera omite los dos argumentos opcionales, mientras que la segunda omite el último argumento.The first omits both optional arguments, while the second omits the last argument. La tercera llamada al método proporciona un argumento posicional para el parámetro necesario, pero usa un argumento con nombre para proporcionar un valor al parámetro description mientras omite el argumento optionalInt.The third method call supplies a positional argument for the required parameter, but uses a named argument to supply a value to the description parameter while omitting the optionalInt argument.

public class Example
{
   public static void Main()
   {
      var opt = new Options();
      opt.ExampleMethod(10);
      opt.ExampleMethod(10, 2);
      opt.ExampleMethod(12, description: "Addition with zero:");
   }
} 
// The example displays the following output:
//      Optional Description: 10 + 0 = 10
//      Optional Description: 10 + 2 = 12
//      Addition with zero:: 12 + 0 = 12

El uso de parámetros opcionales incide en la resolución de sobrecarga o en la manera en que el compilador de C# determina qué sobrecarga en particular debe invocar una llamada al método, como sigue:The use of optional parameters affects overload resolution, or the way in which the C# compiler determines which particular overload should be invoked by a method call, as follows:

  • Un método, indexador o constructor es un candidato para la ejecución si cada uno de sus parámetros es opcional o corresponde, por nombre o por posición, a un solo argumento de la instrucción de llamada y el argumento se puede convertir al tipo del parámetro.A method, indexer, or constructor is a candidate for execution if each of its parameters either is optional or corresponds, by name or by position, to a single argument in the calling statement, and that argument can be converted to the type of the parameter.
  • Si se encuentra más de un candidato, se aplican las reglas de resolución de sobrecarga de las conversiones preferidas a los argumentos que se especifican explícitamente.If more than one candidate is found, overload resolution rules for preferred conversions are applied to the arguments that are explicitly specified. Los argumentos omitidos en parámetros opcionales se ignoran.Omitted arguments for optional parameters are ignored.
  • Si dos candidatos se consideran igualmente correctos, la preferencia pasa a un candidato que no tenga parámetros opcionales cuyos argumentos se hayan omitido en la llamada.If two candidates are judged to be equally good, preference goes to a candidate that does not have optional parameters for which arguments were omitted in the call. Se trata de una consecuencia de una preferencia general en la resolución de sobrecarga para los candidatos con menos parámetros.This is a consequence of a general preference in overload resolution for candidates that have fewer parameters.

Valores devueltosReturn values

Los métodos pueden devolver un valor al autor de llamada.Methods can return a value to the caller. Si el tipo de valor devuelto (el tipo que aparece antes del nombre de método) no es void, el método puede devolver el valor mediante la palabra clave return.If the return type (the type listed before the method name) is not void, the method can return the value by using the return keyword. Una instrucción con la palabra clave return seguida de una variable, una constante o una expresión que coincide con el tipo de valor devuelto devolverá este valor al autor de la llamada al método.A statement with the return keyword followed by a variable, constant, or expression that matches the return type will return that value to the method caller. Los métodos con un tipo de valor devuelto no nulo son necesarios para usar la palabra clave return para devolver un valor.Methods with a non-void return type are required to use the return keyword to return a value. La palabra clave return también detiene la ejecución del método.The return keyword also stops the execution of the method.

Si el tipo de valor devuelto es void, una instrucción return sin un valor también es útil para detener la ejecución del método.If the return type is void, a return statement without a value is still useful to stop the execution of the method. Sin la palabra clave return , el método dejará de ejecutarse cuando alcance el final del bloque de código.Without the return keyword, the method will stop executing when it reaches the end of the code block.

Por ejemplo, estos dos métodos utilizan la palabra clave return para devolver enteros:For example, these two methods use the return keyword to return integers:

class SimpleMath
{
    public int AddTwoNumbers(int number1, int number2)
    {
        return number1 + number2;
    }

    public int SquareANumber(int number)
    {
        return number * number;
    }
}

Para utilizar un valor devuelto de un método, el método de llamada puede usar la llamada de método en cualquier lugar; un valor del mismo tipo sería suficiente.To use a value returned from a method, the calling method can use the method call itself anywhere a value of the same type would be sufficient. También puede asignar el valor devuelto a una variable.You can also assign the return value to a variable. Por ejemplo, los dos siguientes ejemplos de código logran el mismo objetivo:For example, the following two code examples accomplish the same goal:

int result = obj.AddTwoNumbers(1, 2);
result = obj.SquareANumber(result);
// The result is 9.
Console.WriteLine(result);
result = obj.SquareANumber(obj.AddTwoNumbers(1, 2));
// The result is 9.
Console.WriteLine(result);

Usar una variable local, en este caso, result, para almacenar un valor es opcional.Using a local variable, in this case, result, to store a value is optional. La legibilidad del código puede ser útil, o puede ser necesaria si debe almacenar el valor original del argumento para todo el ámbito del método.It may help the readability of the code, or it may be necessary if you need to store the original value of the argument for the entire scope of the method.

A veces, quiere que el método devuelva más que un solo valor.Sometimes, you want your method to return more than a single value. A partir de C# 7.0, puede hacer esto fácilmente mediante tipos de tupla y literales de tupla.Starting with C# 7.0, you can do this easily by using tuple types and tuple literals. El tipo de tupla define los tipos de datos de los elementos de la tupla.The tuple type defines the data types of the tuple's elements. Los literales de tupla proporcionan los valores reales de la tupla devuelta.Tuple literals provide the actual values of the returned tuple. En el ejemplo siguiente, (string, string, string, int) define el tipo de tupla que devuelve el método GetPersonalInfo.In the following example, (string, string, string, int) defines the tuple type that is returned by the GetPersonalInfo method. La expresión (per.FirstName, per.MiddleName, per.LastName, per.Age) es el literal de tupla; el método devuelve el nombre, los apellidos y la edad de un objeto PersonInfo.The expression (per.FirstName, per.MiddleName, per.LastName, per.Age) is the tuple literal; the method returns the first, middle, and last name, along with the age, of a PersonInfo object.

public (string, string, string, int) GetPersonalInfo(string id)
{
    PersonInfo per = PersonInfo.RetrieveInfoById(id);
    return (per.FirstName, per.MiddleName, per.LastName, per.Age);
}

Luego, el autor de la llamada puede usar la tupla devuelta con código como el siguiente:The caller can then consume the returned tuple with code like the following:

var person = GetPersonalInfo("111111111")
Console.WriteLine("{person.Item1} {person.Item3}: age = {person.Item4}");

También se pueden asignar nombres a los elementos de tupla en la definición de tipo de tupla.Names can also be assigned to the tuple elements in the tuple type definition. En el ejemplo siguiente se muestra una versión alternativa del método GetPersonalInfo que usa elementos con nombre:The following example shows an alternate version of the GetPersonalInfo method that uses named elements:

public (string FName, string MName, string LName, int Age) GetPersonalInfo(string id)
{
    PersonInfo per = PersonInfo.RetrieveInfoById(id);
    return (per.FirstName, per.MiddleName, per.LastName, per.Age);
}

La llamada anterior al método GetPersonInfo se puede modificar luego de la manera siguiente:The previous call to the GetPersonInfo method can then be modified as follows:

var person = GetPersonalInfo("111111111");
Console.WriteLine("{person.FName} {person.LName}: age = {person.Age}");

Si a un método se pasa una matriz como argumento y modifica el valor de elementos individuales, no es necesario que el método devuelva la matriz, aunque puede que se prefiera hacerlo a efectos del buen estilo o el flujo funcional de valores.If a method is passed an array as an argument and modifies the value of individual elements, it is not necessary for the method to return the array, although you may choose to do so for good style or functional flow of values. Esto se debe a que C# pasa todos los tipos de referencia por valor, y el valor de una referencia a la matriz es el puntero a la matriz.This is because C# passes all reference types by value, and the value of an array reference is the pointer to the array. En el ejemplo siguiente, los cambios al contenido de la matriz values que se realizan en el método DoubleValues los puede observar cualquier código que tenga una referencia a la matriz.In the following example, changes to the contents of the values array that are made in the DoubleValues method are observable by any code that has a reference to the array.



using System;

public class Example
{
   static void Main(string[] args)  
   {  
      int[] values = { 2, 4, 6, 8 };
      DoubleValues(values);
      foreach (var value in values)
         Console.Write("{0}  ", value);
   }  
  
   public static void DoubleValues(int[] arr)
   {
      for (int ctr = 0; ctr <= arr.GetUpperBound(0); ctr++)
         arr[ctr] = arr[ctr] * 2;
   }
}
// The example displays the following output:
//       4  8  12  16

Métodos de extensiónExtension methods

Normalmente, hay dos maneras de agregar un método a un tipo existente:Ordinarily, there are two ways to add a method to an existing type:

  • Modificar el código fuente del tipo.Modify the source code for that type. No puede hacerlo si no es propietario del código fuente del tipo.You cannot do this, of course, if you do not own the type's source code. Y esto supone un cambio sustancial si también agrega los campos de datos privados para admitir el método.And this becomes a breaking change if you also add any private data fields to support the method.
  • Definir el nuevo método en una clase derivada.Define the new method in a derived class. No se puede agregar un método de este modo con herencia para otros tipos, como estructuras y enumeraciones.A method cannot be added in this way using inheritance for other types, such as structures and enumerations. Tampoco se puede usar para agregar un método a una clase sealed.Nor can it be used to "add" a method to a sealed class.

Los métodos de extensión permiten agregar un método a un tipo existente sin modificar el propio tipo o implementar el nuevo método en un tipo heredado.Extension methods let you "add" a method to an existing type without modifying the type itself or implementing the new method in an inherited type. El método de extensión tampoco tiene que residir en el mismo ensamblado que el tipo que extiende.The extension method also does not have to reside in the same assembly as the type it extends. Llame a un método de extensión como si fuera miembro de un tipo definido.You call an extension method as if it were a defined member of a type.

Para obtener más información, vea Métodos de extensión.For more information, see Extension Methods.

Métodos asincrónicosAsync Methods

Mediante la característica asincrónica, puede invocar métodos asincrónicos sin usar definiciones de llamada explícitas ni dividir manualmente el código en varios métodos o expresiones lambda.By using the async feature, you can invoke asynchronous methods without using explicit callbacks or manually splitting your code across multiple methods or lambda expressions.

Si marca un método con el modificador async, puede usar el operador await en el método.If you mark a method with the async modifier, you can use the await operator in the method. Cuando el control llega a una expresión await en el método asincrónico, el control se devuelve al autor de la llamada si la tarea en espera no se ha completado y se suspende el progreso del método con la palabra clave await hasta que dicha tarea se complete.When control reaches an await expression in the async method, control returns to the caller if the awaited task is not completed, and progress in the method with the await keyword is suspended until the awaited task completes. Cuando se completa la tarea, la ejecución puede reanudarse en el método.When the task is complete, execution can resume in the method.

Nota

Un método asincrónico vuelve al autor de llamada cuando encuentra el primer objeto esperado que aún no se ha completado o cuando llega al final del método asincrónico, lo que ocurra primero.An async method returns to the caller when either it encounters the first awaited object that’s not yet complete or it gets to the end of the async method, whichever occurs first.

Un método asincrónico puede tener un tipo de valor devuelto de Task<TResult>, Task o void.An async method can have a return type of Task<TResult>, Task, or void. El tipo de valor devuelto void se usa principalmente para definir controladores de eventos, donde se requiere un tipo de valor devuelto void.The void return type is used primarily to define event handlers, where a void return type is required. No se puede esperar un método asincrónico que devuelve void y el autor de llamada a un método que no devuelve ningún valor no puede capturar ninguna excepción producida por este.An async method that returns void can't be awaited, and the caller of a void-returning method can't catch exceptions that the method throws. A partir de la versión C# 7.0, el método asincrónico puede tener cualquier tipo de valor devuelto similar a una tarea .Starting with C# 7.0, an async method can have any task-like return type.

En el ejemplo siguiente, DelayAsync es un método asincrónico que contiene una instrucción return que devuelve un entero.In the following example, DelayAsync is an async method that has a return statement that returns an integer. Como se trata de un método asincrónico, su declaración de método debe tener un tipo de valor devuelto de Task<int>.Because it is an async method, its method declaration must have a return type of Task<int>. Dado que el tipo de valor devuelto es Task<int>, la evaluación de la expresión await en DoSomethingAsync genera un entero, como se demuestra en la instrucción int result = await delayTask siguiente.Because the return type is Task<int>, the evaluation of the await expression in DoSomethingAsync produces an integer, as the following int result = await delayTask statement demonstrates.

using System;
using System.Diagnostics;
using System.Threading.Tasks;

public class Example
{
    // This Click event is marked with the async modifier.
    public static void Main()
    {
       DoSomethingAsync().Wait();
    }

    private static async Task DoSomethingAsync()
    {
        int result = await DelayAsync();
        Console.WriteLine("Result: " + result);
    }

    private static async Task<int> DelayAsync()
    {
        await Task.Delay(100);
        return 5;
    }

    // Output:
    //  Result: 5
}
// The example displays the following output:
//        Result: 5

Un método asincrónico no puede declarar ningún parámetro in, ref o out, pero puede llamar a los métodos que tienen estos parámetros.An async method can't declare any in, ref, or out parameters, but it can call methods that have such parameters.

Para obtener más información sobre los métodos asincrónicos, vea Programación asincrónica con Async y Await, Controlar el flujo en los programas asincrónicos y Tipos de valor devueltos asincrónicos.For more information about async methods, see Asynchronous Programming with Async and Await, Control Flow in Async Programs, and Async Return Types.

Miembros con forma de expresiónExpression-bodied members

Es habitual tener definiciones de método que simplemente hacen las devoluciones de forma inmediata con el resultado de una expresión, o que tienen una sola instrucción como cuerpo del método.It is common to have method definitions that simply return immediately with the result of an expression, or that have a single statement as the body of the method. Hay un acceso directo de sintaxis para definir este método mediante =>:There is a syntax shortcut for defining such methods using =>:

public Point Move(int dx, int dy) => new Point(x + dx, y + dy);
public void Print() => Console.WriteLine(First + " " + Last);
// Works with operators, properties, and indexers too.
public static Complex operator +(Complex a, Complex b) => a.Add(b);
public string Name => First + " " + Last;
public Customer this[long id] => store.LookupCustomer(id);

Si el método devuelve void o se trata de un método asincrónico, el cuerpo del método debe ser una expresión de instrucción (igual que con las expresiones lambda).If the method returns void or is an async method, the body of the method must be a statement expression (same as with lambdas). Para propiedades e indexadores, deben ser de solo lectura, y no se usa la palabra clave de descriptor de acceso get.For properties and indexers, they must be read-only, and you do not use the get accessor keyword.

IteratorsIterators

Un iterador realiza una iteración personalizada en una colección, como una lista o matriz.An iterator performs a custom iteration over a collection, such as a list or an array. Un iterador usa la instrucción yield return para devolver los elementos de uno en uno.An iterator uses the yield return statement to return each element one at a time. Cuando se llega a una instrucción yield return, se recuerda la ubicación actual para que el autor de la llamada pueda solicitar el siguiente elemento en la secuencia.When a yield return statement is reached, the current location is remembered so that the caller can request the next element in the sequence.

El tipo de valor devuelto de un iterador puede ser IEnumerable, IEnumerable<T>, IEnumeratoro IEnumerator<T>.The return type of an iterator can be IEnumerable, IEnumerable<T>, IEnumerator, or IEnumerator<T>.

Para obtener más información, consulta Iteradores.For more information, see Iterators.

Vea tambiénSee also