Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Un método es un bloque de código que contiene una serie de instrucciones. Un programa hace que se ejecuten las instrucciones al llamar al método y especificando los argumentos de método necesarios. En C#, todas las instrucciones ejecutadas se realizan en el contexto de un método.
El Main
método es el punto de entrada para cada aplicación de C# y lo llama Common Language Runtime (CLR) cuando se inicia el programa. En una aplicación que usa instrucciones de nivel superior, el compilador genera el Main
método y contiene todas las instrucciones de nivel superior.
Nota:
En este artículo se describen los métodos con nombre. Para obtener información sobre las funciones anónimas, consulte Expresiones lambda.
Firmas de método
Los métodos se declaran en una clase, estructura o interfaz especificando el nivel de acceso, como public
o private
, modificadores opcionales como abstract
o sealed
, el valor devuelto, el nombre del método y cualquier parámetro de método. Estas partes son la firma del método .
Importante
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. Sin embargo, forma parte de la firma del método al determinar la compatibilidad entre un delegado y el método que señala.
Los parámetros de método se incluyen entre paréntesis y están separados por comas. Los paréntesis vacíos indican que el método no requiere parámetros. Esta clase contiene cuatro métodos:
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 must implement this.
public abstract double GetTopSpeed();
}
Acceso a métodos
Llamar a un método en un objeto es como tener acceso a un campo. Después del nombre del objeto, agregue un punto, el nombre del método y paréntesis. Los argumentos se enumeran entre paréntesis y están separados por comas. Por lo tanto, se puede llamar a los métodos de la Motorcycle
clase como en el ejemplo siguiente:
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 {speed}");
}
}
Parámetros de método frente a argumentos
La definición del método especifica los nombres y tipos de todos los parámetros necesarios. Cuando el código llama al método, proporciona valores concretos denominados argumentos para cada parámetro. Los argumentos deben ser compatibles con el tipo de parámetro, pero el nombre del argumento (si existe) usado en el código de llamada no tiene que ser el mismo que el parámetro denominado definido en el método . Por ejemplo:
public void Caller()
{
int numA = 4;
// Call with an int variable.
int productA = Square(numA);
int numB = 32;
// Call with another int variable.
int productB = Square(numB);
// Call with an integer literal.
int productC = Square(12);
// Call with an expression that evaluates to int.
productC = Square(productA * 3);
}
int Square(int i)
{
// Store input argument in a local variable.
int input = i;
return input * input;
}
Pasar por referencia frente a pasar por valor
De forma predeterminada, cuando se pasa una instancia de un tipo de valor a un método, su copia se pasa en lugar de la propia instancia. Por lo tanto, los cambios en el argumento no tienen ningún efecto en la instancia original del método de llamada. Para pasar una instancia de tipo valor por referencia, use la ref
palabra clave . Para obtener más información, vea Pasar parámetros Value-Type.
Cuando se pasa un objeto de un tipo de referencia a un método, se pasa una referencia al objeto . Es decir, el método no recibe el propio objeto, sino un argumento que indica la ubicación del objeto. Si cambia un miembro del objeto mediante esta referencia, el cambio se refleja en el argumento del método de llamada, incluso si pasa el objeto por valor.
Cree un tipo de referencia mediante la class
palabra clave , como se muestra en el ejemplo siguiente:
public class SampleRefType
{
public int value;
}
Ahora, si pasa un objeto basado en este tipo a un método, se pasa una referencia al objeto . En el ejemplo siguiente se pasa un objeto de tipo SampleRefType
al método ModifyObject
:
public static void TestRefType()
{
SampleRefType rt = new SampleRefType();
rt.value = 44;
ModifyObject(rt);
Console.WriteLine(rt.value);
}
static void ModifyObject(SampleRefType obj)
{
obj.value = 33;
}
El ejemplo hace básicamente lo mismo que el ejemplo anterior en que pasa un argumento por valor a un método. Pero, dado que se usa un tipo de referencia, el resultado es diferente. La modificación que se realiza en el campo ModifyObject
del parámetro value
, también cambia el campo obj
del argumento value
en el método rt
. El TestRefType
método muestra 33 como salida.
Para obtener más información sobre cómo pasar tipos de referencia por referencia y por valor, vea Pasar Reference-Type parámetros y tipos de referencia.
Valores devueltos
Los métodos pueden devolver un valor al autor de llamada. Si el tipo de valor devuelto (el tipo enumerado antes del nombre del método) no void
es , el método puede devolver el valor mediante la return
instrucción . Una instrucción con la return
palabra clave seguida de un valor que coincida con el tipo de valor devuelto devolverá ese valor al llamador del método.
El valor se puede devolver al autor de la llamada por valor o por referencia. Los valores se devuelven al llamador por referencia si la palabra clave ref
se usa en la firma de método y sigue cada palabra clave return
. Por ejemplo, la siguiente firma de método y la instrucción return indican que el método devuelve una variable denominada estDistance
por referencia al autor de la llamada.
public ref double GetEstimatedDistance()
{
return ref estDistance;
}
La palabra clave return
también detiene la ejecución del método. 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. Sin la return
palabra clave , el método dejará de ejecutarse cuando llegue al final del bloque de código. Se requieren métodos con un tipo de valor devuelto no nulo para usar la return
palabra clave para devolver un valor. Por ejemplo, estos dos métodos utilizan la palabra clave return
para devolver enteros:
class SimpleMath
{
public int AddTwoNumbers(int number1, int number2)
{
return number1 + number2;
}
public int SquareANumber(int number)
{
return number * number;
}
}
Para usar un valor devuelto desde un método, el método de llamada puede usar la propia llamada al método en cualquier lugar donde un valor del mismo tipo sería suficiente. También puede asignar el valor devuelto a una variable. Por ejemplo, los dos ejemplos de código siguientes logran el mismo objetivo:
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);
El uso de una variable local, en este caso, result
, para almacenar un valor es opcional. Puede ayudar a la legibilidad del código o puede ser necesario si necesita almacenar el valor original del argumento para todo el ámbito del método.
Para usar un valor devuelto por referencia desde un método, debe declarar una variable local ref si piensa modificar su valor. Por ejemplo, si el Planet.GetEstimatedDistance
método devuelve un Double valor por referencia, puede definirlo como una variable local ref con código como el siguiente:
ref double distance = ref Planet.GetEstimatedDistance();
No es necesario devolver una matriz multidimensional de un método , M
que modifica el contenido de la matriz si la función que realiza la llamada pasó la matriz a M
. Puede retornar la matriz resultante de M
para mantener un buen estilo o un flujo funcional de valores, pero no es necesario porque C# pasa todos los tipos de referencia por valor y el valor de una referencia de matriz es el puntero a la matriz. En el método M
, los cambios realizados en el contenido de la matriz son observables por cualquier código que tenga una referencia a la matriz, como se muestra en el ejemplo siguiente:
static void Main(string[] args)
{
int[,] matrix = new int[2, 2];
FillMatrix(matrix);
// matrix is now full of -1
}
public static void FillMatrix(int[,] matrix)
{
for (int i = 0; i < matrix.GetLength(0); i++)
{
for (int j = 0; j < matrix.GetLength(1); j++)
{
matrix[i, j] = -1;
}
}
}
Métodos asincrónicos
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.
Si marca un método con el modificador async, puede usar el operador await en el método. Cuando el control alcanza una expresión await en el método asincrónico, el control se devuelve al autor de llamada y se progreso del método se suspende hasta que se completa la tarea esperada. Cuando se completa la tarea, la ejecución puede reanudarse en el método.
Nota:
Un método asincrónico vuelve al autor de la 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.
Normalmente, un método asincrónico tiene un tipo de valor devuelto de Task<TResult>, TaskIAsyncEnumerable<T>o void
. El tipo de valor devuelto void
se usa principalmente para definir controladores de eventos, donde se requiere un tipo de valor devuelto void
. 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. Un método asincrónico puede tener cualquier tipo de valor devuelto que sea como una tarea.
En el ejemplo siguiente, DelayAsync
es un método asincrónico que tiene un tipo de valor devuelto de Task<TResult>.
DelayAsync
tiene una return
instrucción que devuelve un entero. Por lo tanto, la declaración de método de DelayAsync
debe tener un tipo de valor devuelto de Task<int>
. Dado que el tipo de valor devuelto es Task<int>
, la evaluación de la await
expresión en DoSomethingAsync
genera un entero como se muestra en la siguiente instrucción: int result = await delayTask
.
El Main
método es un ejemplo de un método asincrónico que tiene un tipo de valor devuelto de Task. Va al método DoSomethingAsync
y, dado que se expresa con una sola línea, puede omitir las palabras clave async
y await
. Dado que DoSomethingAsync
es un método asincrónico, la tarea de la llamada a DoSomethingAsync
debe esperarse, como se muestra en la siguiente instrucción: await DoSomethingAsync();
.
class Program
{
static Task Main() => DoSomethingAsync();
static async Task DoSomethingAsync()
{
Task<int> delayTask = DelayAsync();
int result = await delayTask;
// The previous two statements may be combined into
// the following statement.
//int result = await DelayAsync();
Console.WriteLine($"Result: {result}");
}
static async Task<int> DelayAsync()
{
await Task.Delay(100);
return 5;
}
}
// Example output:
// Result: 5
Un método asincrónico no puede declarar ningún parámetro ref o out , pero puede llamar a métodos que tienen estos parámetros.
Para obtener más información sobre los métodos asincrónicos, consulte los artículos Programación asincrónica con async y await y Tipos de valor devueltos asincrónicos.
Definiciones de cuerpo de expresión
Es habitual tener definiciones de método que simplemente devuelvan inmediatamente con el resultado de una expresión o que tengan una sola instrucción como cuerpo del método. Hay un atajo de sintaxis para definir estos métodos mediante =>
:
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 es un método asincrónico, el cuerpo del método debe ser una expresión de instrucción (igual que con lambdas). En el caso de las propiedades y los indexadores, estos deben ser de solo lectura y no se debe usar la palabra clave de acceso get
.
Iteradores
Un iterador realiza una iteración personalizada en una colección, como una lista o matriz. Un iterador utiliza la instrucción yield return para devolver cada elemento de uno en uno. Cuando se alcanza una instrucción yield return
, se recuerda la ubicación actual en el código. La ejecución se reinicia desde esa ubicación cuando se llama al iterador la próxima vez.
Se llama a un iterador desde el código de cliente mediante una instrucción foreach .
El tipo de valor devuelto de un iterador puede ser IEnumerable, IEnumerable<T>, IAsyncEnumerable<T>, IEnumerator o IEnumerator<T>.
Para más información, consulta Iteradores.
Especificación del lenguaje C#
Para obtener más información, consulte la Especificación del lenguaje C#. La especificación del lenguaje es el origen definitivo de la sintaxis y el uso de C#.