Sunteți pe pagina 1din 192

Table of Contents

Clases y structs
Clases
Objects
Estructuras
Utilizar estructuras
Herencia
Polimorfismo
Control de versiones con las palabras clave Override y New
Saber cundo utilizar las palabras clave Override y New
Cmo: Invalidar el mtodo ToString
Clases y miembros de clase abstractos y sellados
Cmo: Definir propiedades abstractas
Clases estticas y sus miembros
Miembros
Modificadores de acceso
Campos
Constantes
Cmo: Definir constantes en C#
Propiedades
Utilizar propiedades
Propiedades de interfaz
Restringir la accesibilidad del descriptor de acceso
Cmo: Declarar y usar propiedades de lectura y escritura
Propiedades autoimplementadas
Cmo: Implementar una clase ligera con propiedades autoimplementadas
Mtodos
Funciones locales
Devoluciones y variables locales ref
Pasar parmetros
Variables locales con asignacin implcita de tipos
Mtodos de extensin
Argumentos opcionales y con nombre
Constructores
Utilizar constructores
Constructores de instancias
Constructores privados
Constructores estticos
Cmo: Escribir un constructor Copy
Finalizadores
Inicializadores de objeto y coleccin
Cmo: Inicializar un objeto usando un inicializador de objeto
Cmo: Inicializar un diccionario con un inicializador de coleccin
Cmo: Obtener acceso a una clase de coleccin mediante Foreach
Tipos anidados
Clases y mtodos parciales
Tipos annimos
Cmo: Devolver subconjuntos de propiedades de elementos en una consulta
Clases y structs (Gua de programacin de C#)
03/10/2017 6 min to read Edit Online

Las clases y estructuras son dos de las construcciones bsicas de Common Type System en .NET Framework.
Cada una de ellas es bsicamente una estructura de datos que encapsula un conjunto de datos y
comportamientos que forman un conjunto como una unidad lgica. Los datos y comportamientos son los
miembros de la clase o estructura, e incluyen sus mtodos, propiedades y eventos, entre otros elementos, como
se muestra ms adelante en este tema.
Una declaracin de clase o estructura es como un plano que se utiliza para crear instancias u objetos en tiempo
de ejecucin. Si define una clase o estructura llamada Person , Person es el nombre del tipo. Si declara e
inicializa una variable p de tipo Person , se dice que p es un objeto o instancia de Person . Se pueden crear
varias instancias del mismo tipo Person , y cada instancia tiene diferentes valores en sus propiedades y campos.
Una clase es un tipo de referencia. Cuando se crea un objeto de la clase, la variable a la que se asigna el objeto
contiene solo una referencia a esa memoria. Cuando la referencia de objeto se asigna a una nueva variable, la
nueva variable hace referencia al objeto original. Los cambios realizados en una variable se reflejan en la otra
variable porque ambas hacen referencia a los mismos datos.
Una estructura es un tipo de valor. Cuando se crea una estructura, la variable a la que se asigna la estructura
contiene los datos reales de ella. Cuando la estructura se asigna a una nueva variable, se copia. Por lo tanto, la
nueva variable y la variable original contienen dos copias independientes de los mismos datos. Los cambios
realizados en una copia no afectan a la otra copia.
En general, las clases se utilizan para modelar comportamientos ms complejos, o datos que se prevn modificar
despus de haber creado un objeto de clase. Las estructuras son ms adecuadas para las estructuras de datos
pequeas que contienen principalmente datos que no se prevn modificar despus de haber creado la
estructura.
Para ms informacin, vea Clases, Objectos y Estructuras.

Ejemplo
En el ejemplo siguiente, CustomClass en el espacio de nombres ProgrammingGuide tiene tres miembros: un
constructor de instancia, una propiedad denominada Number y un mtodo denominado Multiply . El mtodo
Main de la clase Program crea una instancia (objeto) de CustomClass , y se puede acceder a la propiedad y al
mtodo del objeto mediante una notacin de puntos.
using System;

namespace ProgrammingGuide
{
// Class definition.
public class CustomClass
{
// Class members.
//
// Property.
public int Number { get; set; }

// Method.
public int Multiply(int num)
{
return num * Number;
}

// Instance Constructor.
public CustomClass()
{
Number = 0;
}
}

// Another class definition that contains Main, the program entry point.
class Program
{
static void Main(string[] args)
{
// Create an object of type CustomClass.
CustomClass custClass = new CustomClass();

// Set the value of the public property.


custClass.Number = 27;

// Call the public method.


int result = custClass.Multiply(4);
Console.WriteLine($"The result is {result}.");
}
}
}
// The example displays the following output:
// The result is 108.

Encapsulacin
A veces se hace referencia a la encapsulacin como el primer pilar o principio de la programacin orientada a
objetos. Segn el principio de encapsulacin, una clase o una estructura pueden especificar hasta qu punto se
puede acceder a sus miembros para codificar fuera de la clase o la estructura. No se prev el uso de los mtodos
y las variables fuera de la clase, o el ensamblado puede ocultarse para limitar el potencial de los errores de
codificacin o de los ataques malintencionados.
Para ms informacin sobre las clases, vea Clases y Objetos.
Miembros
Todos los mtodos, campos, constantes, propiedades y eventos deben declararse dentro de un tipo; se les
denomina miembros del tipo. En C#, no hay mtodos ni variables globales como en otros lenguajes. Incluso un
punto de entrada del programa, el mtodo Main , debe declararse dentro de una clase o estructura. La lista
siguiente incluye los diversos tipos de miembros que se pueden declarar en una clase o estructura.
Campos
Constantes
Propiedades
Mtodos
Constructores
Eventos
Finalizadores
Indizadores
Operadores
Tipos anidados
Accesibilidad
Algunos mtodos y propiedades estn diseados para ser invocables y accesibles desde el cdigo fuera de la
clase o la estructura, lo que se conoce como cdigo de cliente. Otros mtodos y propiedades pueden estar
indicados exclusivamente para utilizarse en la propia clase o estructura. Es importante limitar la accesibilidad del
cdigo, a fin de que solo el cdigo de cliente previsto pueda acceder a l. Puede usar los modificadores de
acceso public, protected, internal, protected internal y private para especificar hasta qu punto los tipos y sus
miembros son accesibles para el cdigo de cliente. La accesibilidad predeterminada es private . Para ms
informacin, vea Modificadores de acceso.
Herencia
Las clases (pero no las estructuras) admiten el concepto de herencia. Una clase que deriva de otra clase (la clase
base) contiene automticamente todos los miembros pblicos, protegidos e internos de la clase base, salvo sus
constructores y finalizadores. Para ms informacin, vea Herencia y Polimorfismo.
Las clases pueden declararse como abstract, lo que significa que uno o varios de sus mtodos no tienen ninguna
implementacin. Aunque no se pueden crear instancias de clases abstractas directamente, pueden servir como
clases base para otras clases que proporcionan la implementacin que falta. Las clases tambin pueden
declararse como sealed para evitar que otras clases hereden de ellas. Para ms informacin, vea Clases y
miembros de clase abstractos y sellados.
Interfaces
Las clases y las estructuras pueden heredar varias interfaces. Heredar de una interfaz significa que el tipo
implementa todos los mtodos definidos en la interfaz. Para ms informacin, vea Interfaces.
Tipos genricos
Las clases y estructuras pueden definirse con uno o varios parmetros de tipo. El cdigo de cliente proporciona
el tipo cuando crea una instancia del tipo. Por ejemplo, la clase List<T> del espacio de nombres
System.Collections.Generic se define con un parmetro de tipo. El cdigo de cliente crea una instancia de
List<string> o List<int> para especificar el tipo que contendr la lista. Para ms informacin, vea Genricos.

Tipos estticos
Las clases (pero no las estructuras) pueden declararse como static. Una clase esttica puede contener solo
miembros estticos y no se puede crear una instancia de ellos con la palabra clave new. Una copia de la clase se
carga en memoria cuando se carga el programa, y sus miembros son accesibles a travs del nombre de clase.
Las clases y estructuras pueden contener miembros estticos. Para ms informacin, vea Clases estticas y sus
miembros.
Tipos anidados
Una clase o estructura se puede anidar dentro de otra clase o estructura. Para obtener ms informacin, consulte
Tipos anidados.
Tipos parciales
Puede definir parte de una clase, estructura o mtodo en un archivo de cdigo y otra parte en un archivo de
cdigo independiente. Para ms informacin, vea Clases y mtodos parciales.
Inicializadores de objeto
Puede crear instancias de objetos de clase o estructura y de colecciones de objetos e iniciarlizarlos, sin llamar de
forma explcita a su constructor. Para ms informacin, vea Inicializadores de objeto y de coleccin.
Tipos annimos
En situaciones donde no es conveniente o necesario crear una clase con nombre, por ejemplo al rellenar una
lista con estructuras de datos que no tiene que conservar o pasar a otro mtodo, utilice los tipos annimos. Para
ms informacin, vea Tipos annimos.
mtodos de extensin.
Puede "extender" una clase sin crear una clase derivada mediante la creacin de un tipo independiente cuyos
mtodos pueden llamarse como si pertenecieran al tipo original. Para ms informacin, vea Mtodos de
extensin.
Variables locales con asignacin implcita de tipos
Dentro de un mtodo de clase o estructura, puede utilizar tipos implcitos para indicar al compilador que
determine el tipo correcto en tiempo de compilacin. Para ms informacin, vea Variables locales con asignacin
implcita de tipos.

Especificacin del lenguaje C#


Para obtener ms informacin, consulte la Especificacin del lenguaje C#. La especificacin del lenguaje es la
fuente definitiva de la sintaxis y el uso de C#.

Vea tambin
Gua de programacin de C#
Clases (Gua de programacin de C#)
03/10/2017 5 min to read Edit Online

Una class es una construccin que le permite crear sus propios tipos personalizados agrupando las variables de
otros tipos, mtodos y eventos. Una clase es como un plano. Define los datos y el comportamiento de un tipo. Si la
clase no se declara como esttica, el cdigo de cliente puede usarla mediante la creacin de objetos o instancias
que se asignan a una variable. La variable permanece en memoria hasta que todas las referencias a ella estn
fuera del mbito. En ese momento, CLR la marca como apta para la recoleccin de elementos no utilizados. Si la
clase se declara como esttica, solo habr una copia en la memoria y el cdigo de cliente solo podr tener acceso a
ella a travs de la propia clase, y no a travs de una variable de instancia. Para obtener ms informacin, vea
Clases estticas y sus miembros.
A diferencia de los structs, las clases admiten la herencia, una caracterstica fundamental de la programacin
orientada a objetos. Para obtener ms informacin, vea Herencia.

Declarar clases
Las clases se declaran mediante la palabra clave class, como se muestra en el siguiente ejemplo:

public class Customer


{
//Fields, properties, methods and events go here...
}

La palabra clave class va precedida del nivel de acceso. Como en este caso se usa public, cualquier usuario puede
crear objetos de esta clase. El nombre de la clase sigue a la palabra clave class . El resto de la definicin es el
cuerpo de la clase, donde se definen los datos y el comportamiento. Los campos, las propiedades, los mtodos y
los eventos de una clase se denominan de forma colectiva miembros de clase.

Crear objetos
Aunque a veces se usan indistintamente, una clase y un objeto son cosas diferentes. Una clase define un tipo de
objeto, pero no es un objeto en s. Un objeto es una entidad concreta basada en una clase y, a veces, se conoce
como una instancia de una clase.
Los objetos se pueden crear usando la palabra clave new, seguida del nombre de la clase en la que se basar el
objeto, como en este ejemplo:

Customer object1 = new Customer();

Cuando se crea una instancia de una clase, se vuelve a pasar al programador una referencia al objeto. En el
ejemplo anterior, object1 es una referencia a un objeto que se basa en Customer . Esta referencia apunta al objeto
nuevo, pero no contiene los datos del objeto. De hecho, puede crear una referencia de objeto sin tener que crear
ningn objeto:

Customer object2;

No se recomienda crear referencias de objeto como esta, que no hace referencia a ningn objeto, ya que, si se
intenta obtener acceso a un objeto a travs de este tipo de referencia, se producir un error en tiempo de
ejecucin. Pero dicha referencia puede haberse creado para hacer referencia a un objeto, ya sea creando un nuevo
objeto o asignndola a un objeto existente, como en el siguiente ejemplo:

Customer object3 = new Customer();


Customer object4 = object3;

Este cdigo crea dos referencias de objeto que hacen referencia al mismo objeto. Por lo tanto, los cambios
efectuados en el objeto mediante object3 se reflejarn en los usos posteriores de object4 . Dado que los objetos
basados en clases se tratan por referencia, las clases se denominan "tipos de referencia".

Herencia de clases
La herencia se consigue mediante una derivacin, en la que se declara una clase mediante una clase base, desde la
que hereda los datos y el comportamiento. Una clase base se especifica anexando dos puntos y el nombre de la
clase base seguido del nombre de la clase derivada, como en el siguiente ejemplo:

public class Manager : Employee


{
// Employee fields, properties, methods and events are inherited
// New Manager fields, properties, methods and events go here...
}

Cuando una clase declara una clase base, hereda todos los miembros de la clase base excepto los constructores.
A diferencia de C++, una clase de C# solo puede heredar directamente de una clase base. En cambio, dado que
una clase base puede heredar de otra clase, una clase podra heredar indirectamente varias clases base. Adems,
una clase puede implementar directamente ms de una interfaz. Para obtener ms informacin, vea Interfaces.
Una clase puede declararse abstracta. Una clase abstracta contiene mtodos abstractos que tienen una definicin
de firma, pero no tienen ninguna implementacin. No se pueden crear instancias de las clases abstractas. Solo se
pueden usar a travs de las clases derivadas que implementan los mtodos abstractos. Por el contrario, la clase
sealed no permite que otras clases se deriven de ella. Para ms informacin, vea Clases y miembros de clase
abstractos y sellados.
Las definiciones de clase se pueden dividir entre distintos archivos de cdigo fuente. Para obtener ms
informacin, consulte Clases y mtodos parciales.

Descripcin
En el ejemplo siguiente se define una clase pblica que contiene un solo campo, un mtodo y un mtodo especial
denominado "constructor". Para obtener ms informacin, vea Constructores. Luego, se crea una instancia de la
clase con la palabra clave new .

Ejemplo
public class Person
{
// Field
public string name;

// Constructor that takes no arguments.


public Person()
{
name = "unknown";
}

// Constructor that takes one argument.


public Person(string nm)
{
name = nm;
}

// Method
public void SetName(string newName)
{
name = newName;
}
}
class TestPerson
{
static void Main()
{
// Call the constructor that has no parameters.
Person person1 = new Person();
Console.WriteLine(person1.name);

person1.SetName("John Smith");
Console.WriteLine(person1.name);

// Call the constructor that has one parameter.


Person person2 = new Person("Sarah Jones");
Console.WriteLine(person2.name);

// Keep the console window open in debug mode.


Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
// Output:
// unknown
// John Smith
// Sarah Jones

Especificacin del lenguaje C#


Para obtener ms informacin, consulte la Especificacin del lenguaje C#. La especificacin del lenguaje es la
fuente definitiva de la sintaxis y el uso de C#.

Vea tambin
Gua de programacin de C#
Object-Oriented Programming (Programacin orientada a objetos)
Polimorfismo
Miembros
Mtodos
Constructors (Constructores [Gua de programacin de C#])
Finalizadores
Objects
Objetos (Gua de programacin de C#)
03/10/2017 5 min to read Edit Online

Una definicin de clase o estructura es como un plano que especifica qu puede hacer el tipo. Un objeto es
bsicamente un bloque de memoria que se ha asignado y configurado de acuerdo con el plano. Un programa
puede crear muchos objetos de la misma clase. Los objetos tambin se denominan instancias y pueden
almacenarse en una variable con nombre, o en una matriz o coleccin. El cdigo de cliente es el cdigo que usa
estas variables para llamar a los mtodos y acceder a las propiedades pblicas del objeto. En un lenguaje orientado
a objetos, como C#, un programa tpico consta de varios objetos que interactan dinmicamente.

NOTA
Los tipos estticos se comportan de forma diferente a lo que se describe aqu. Para obtener ms informacin, consulte Clases
estticas y sus miembros.

Instancias de estructura frente a Instancias de clase


Puesto que las clases son tipos de referencia, una variable de un objeto de clase contiene una referencia a la
direccin del objeto del montn administrado. Si se asigna un segundo objeto del mismo tipo al primer objeto,
ambas variables hacen referencia al objeto de esa direccin. Este punto se analiza con ms detalle ms adelante en
este tema.
Las instancias de clases se crean mediante el operador new. En el ejemplo siguiente, Person es el tipo, y person1 y
person 2 son instancias u objetos de ese tipo.
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Person(string name, int age)
{
Name = name;
Age = age;
}
//Other properties, methods, events...
}

class Program
{
static void Main()
{
Person person1 = new Person("Leopold", 6);
Console.WriteLine("person1 Name = {0} Age = {1}", person1.Name, person1.Age);

// Declare new person, assign person1 to it.


Person person2 = person1;

//Change the name of person2, and person1 also changes.


person2.Name = "Molly";
person2.Age = 16;

Console.WriteLine("person2 Name = {0} Age = {1}", person2.Name, person2.Age);


Console.WriteLine("person1 Name = {0} Age = {1}", person1.Name, person1.Age);

// Keep the console open in debug mode.


Console.WriteLine("Press any key to exit.");
Console.ReadKey();

}
}
/*
Output:
person1 Name = Leopold Age = 6
person2 Name = Molly Age = 16
person1 Name = Molly Age = 16
*/

Dado que las estructuras son tipos de valor, una variable de un objeto de estructura contiene una copia de todo el
objeto. Tambin se pueden crear instancias de estructuras usando el operador new , pero esto no resulta necesario,
como se muestra en el ejemplo siguiente:
public struct Person
{
public string Name;
public int Age;
public Person(string name, int age)
{
Name = name;
Age = age;
}
}

public class Application


{
static void Main()
{
// Create struct instance and initialize by using "new".
// Memory is allocated on thread stack.
Person p1 = new Person("Alex", 9);
Console.WriteLine("p1 Name = {0} Age = {1}", p1.Name, p1.Age);

// Create new struct object. Note that struct can be initialized


// without using "new".
Person p2 = p1;

// Assign values to p2 members.


p2.Name = "Spencer";
p2.Age = 7;
Console.WriteLine("p2 Name = {0} Age = {1}", p2.Name, p2.Age);

// p1 values remain unchanged because p2 is copy.


Console.WriteLine("p1 Name = {0} Age = {1}", p1.Name, p1.Age);

// Keep the console open in debug mode.


Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
/*
Output:
p1 Name = Alex Age = 9
p2 Name = Spencer Age = 7
p1 Name = Alex Age = 9
*/

La memoria para p1 y p2 se asigna en la pila de subprocesos. Esta memoria se reclama junto con el tipo o
mtodo en el que se declara. Este es uno de los motivos por los que se copian las estructuras en la asignacin. Por
el contrario, la memoria que se asigna a una instancia de clase la reclama automticamente (recoleccin de
elementos no utilizados) Common Language Runtime cuando todas las referencias al objeto se han salido del
mbito. No es posible destruir de forma determinante un objeto de clase como en C++. Para obtener ms
informacin sobre la recoleccin de elementos no utilizados en .NET Framework, consulte Recoleccin de
elementos no utilizados.

NOTA
La asignacin y desasignacin de memoria en el montn administrado estn muy optimizadas en Common Language
Runtime. En la mayora de los casos, no existe ninguna diferencia significativa en el costo de rendimiento entre asignar una
instancia de clase en el montn y asignar una instancia de estructura en la pila.

Identidad de objeto frente a igualdad de valores


Cuando se comparan dos objetos para comprobar si son iguales, primero debe determinar si quiere saber si las
dos variables representan el mismo objeto en la memoria o si los valores de uno o varios de sus campos son
equivalentes. Si tiene previsto comparar valores, debe tener en cuenta si los objetos son instancias de tipos de
valor (estructuras) o tipos de referencia (clases, delegados y matrices).
Para determinar si dos instancias de clase hacen referencia a la misma ubicacin en la memoria (lo que
significa que tienen la misma identidad), use el mtodo esttico Equals. (System.Object es la clase base
implcita para todos los tipos de valor y tipos de referencia, incluidas las clases y estructuras definidas por el
usuario).
Para determinar si los campos de instancia de dos instancias de estructura presentan los mismos valores,
use el mtodo ValueType.Equals. Dado que todas las estructuras heredan implcitamente de
System.ValueType, se llama al mtodo directamente en el objeto, como se muestra en el ejemplo siguiente:

// Person is defined in the previous example.

//public struct Person


//{
// public string Name;
// public int Age;
// public Person(string name, int age)
// {
// Name = name;
// Age = age;
// }
//}

Person p1 = new Person("Wallace", 75);


Person p2;
p2.Name = "Wallace";
p2.Age = 75;

if (p2.Equals(p1))
Console.WriteLine("p2 and p1 have the same values.");

// Output: p2 and p1 have the same values.

La implementacin System.ValueType de Equals usa la reflexin porque debe poder determinar cules son los
campos en cualquier estructura. Al crear sus propias estructuras, invalide el mtodo Equals para proporcionar un
algoritmo de igualdad eficaz especfico de su tipo.
Para determinar si los valores de los campos de dos instancias de clase son iguales, puede usar el mtodo
Equals o el operador ==. En cambio, selos solo si la clase los ha invalidado o sobrecargado para proporcionar
una definicin personalizada de lo que significa "igualdad" para los objetos de ese tipo. La clase tambin puede
implementar la interfaz IEquatable<T> o la interfaz IEqualityComparer<T>. Ambas interfaces proporcionan
mtodos que pueden servir para comprobar la igualdad de valores. Al disear sus propias clases que invaliden
Equals , asegrese de seguir las instrucciones descritas en Cmo: Definir la igualdad de valores para un tipo y
Object.Equals(Object).

Secciones relacionadas
Para obtener ms informacin:
Clases
Estructuras
Constructores
Finalizadores
Eventos

Vea tambin
Gua de programacin de C#
object
Herencia
class
struct
new (Operador, Referencia de C#)
Sistema de tipos comunes
Structs (Gua de programacin de C#)
03/10/2017 1 min to read Edit Online

Los structs se definen mediante la palabra clave struct, por ejemplo:

public struct PostalAddress


{
// Fields, properties, methods and events go here...
}

Los structs comparten la mayora de la sintaxis con las clases, aunque estn ms limitados que estas:
Dentro de una declaracin de struct, los campos no se pueden inicializar a menos que se declaren como
constantes o estticos.
Un struct no puede declarar un constructor predeterminado (un constructor sin parmetros) ni un
finalizador.
Los structs se copian en la asignacin. Cuando se asigna un struct a una variable nueva, se copian todos los
datos y las modificaciones que se realicen en la nueva copia no cambiarn los datos de la copia original. Es
importante que lo recuerde al trabajar con colecciones de tipos de valor como Dictionary<string,
myStruct>.
Los structs son tipos de valor y las clases son tipos de referencia.
A diferencia de las clases, se pueden crear instancias de structs sin usar un operador new .
Los structs pueden declarar constructores que tengan parmetros.
As, un struct no puede heredar de otra clase o de otro struct, como tampoco puede ser la base de una clase.
Todos los structs heredan directamente de System.ValueType , que hereda de System.Object .
Un struct puede implementar interfaces.
Un struct se puede usar como un tipo que acepta valores NULL y se le puede asignar un valor NULL.

Secciones relacionadas
Para obtener ms informacin:
Utilizar estructuras
Constructores
Tipos que aceptan valores NULL
Cmo: Saber las diferencias entre pasar a un mtodo un struct y una referencia a clase
Cmo: Implementar conversiones definidas por el usuario entre structs

Vea tambin
Gua de programacin de C#
Clases y estructuras
Clases
Utilizar estructuras (Gua de programacin de C#)
03/10/2017 3 min to read Edit Online

El tipo struct resulta adecuado para representar objetos pequeos como Point , Rectangle y Color . Aunque es
igual de vlido representar un punto como un elemento class con Propiedades autoimplementadas, seguramente
un struct sea ms eficaz en algunos escenarios. Por ejemplo, si declara una matriz de 1000 objetos Point , se
asignar ms memoria para hacer referencia a cada objeto y, en este caso, un struct sera menos costoso. Como
.NET Framework contiene un objeto denominado Point, denominaremos el struct de este ejemplo "CoOrds".

public struct CoOrds


{
public int x, y;

public CoOrds(int p1, int p2)


{
x = p1;
y = p2;
}
}

Definir un constructor (sin parmetros) predeterminado para un struct es un error, como tambin lo es inicializar
un campo de instancia en el cuerpo de un struct. Los miembros del struct solo se pueden inicializar mediante un
constructor con parmetros, o bien teniendo acceso individualmente a cada miembro una vez declarado el struct.
Los miembros privados o inaccesibles por cualquier otro motivo solo se pueden inicializar en un constructor.
Cuando se crea un objeto de struct mediante el operador new , el objeto se crea y se llama al constructor
apropiado. A diferencia de las clases, se pueden crear instancias de structs sin usar el operador new . En tal caso,
no hay ninguna llamada de constructor, con lo cual la asignacin es ms eficaz. Pero los campos seguirn sin
asignar y el objeto no se podr usar hasta que todos los campos se inicialicen.
Cuando un struct contiene un tipo de referencia como miembro, se debe invocar explcitamente el constructor
predeterminado de ese miembro, ya que, de lo contrario, el miembro seguir sin asignar y el struct no se podr
usar (esto genera el error del compilador CS0171).
En los structs no existe el concepto de herencia que s hay en las clases. As, un struct no puede heredar de otra
clase o de otro struct, como tampoco puede ser la base de una clase. Pero los structs s heredan de la clase base
Object. Un struct puede implementar interfaces y lo hace exactamente igual que las clases.
No se puede declarar una clase mediante la palabra clave struct . En C#, las clases y los structs son distintos
semnticamente. Un struct es un tipo de valor, mientras que una clase es un tipo de referencia. Para obtener ms
informacin, vea Tipos de valor.
A menos que necesite una semntica de tipo de referencia, es probable que el sistema controle una clase pequea
ms eficazmente si se declara como un struct.

Ejemplo 1
Descripcin
En este ejemplo se muestra la inicializacin de struct mediante constructores predeterminados y constructores
con parmetros.
Cdigo
public struct CoOrds
{
public int x, y;

public CoOrds(int p1, int p2)


{
x = p1;
y = p2;
}
}

// Declare and initialize struct objects.


class TestCoOrds
{
static void Main()
{
// Initialize:
CoOrds coords1 = new CoOrds();
CoOrds coords2 = new CoOrds(10, 10);

// Display results:
Console.Write("CoOrds 1: ");
Console.WriteLine("x = {0}, y = {1}", coords1.x, coords1.y);

Console.Write("CoOrds 2: ");
Console.WriteLine("x = {0}, y = {1}", coords2.x, coords2.y);

// Keep the console window open in debug mode.


Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
/* Output:
CoOrds 1: x = 0, y = 0
CoOrds 2: x = 10, y = 10
*/

Ejemplo 2
Descripcin
En este ejemplo se muestra una caracterstica nica de los structs. Se crea un objeto CoOrds sin usar el operador
new . Si reemplaza la palabra struct por la palabra class , el programa no se compilar.

Cdigo

public struct CoOrds


{
public int x, y;

public CoOrds(int p1, int p2)


{
x = p1;
y = p2;
}
}
// Declare a struct object without "new."
class TestCoOrdsNoNew
{
static void Main()
{
// Declare an object:
CoOrds coords1;

// Initialize:
coords1.x = 10;
coords1.y = 20;

// Display results:
Console.Write("CoOrds 1: ");
Console.WriteLine("x = {0}, y = {1}", coords1.x, coords1.y);

// Keep the console window open in debug mode.


Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
// Output: CoOrds 1: x = 10, y = 20

Vea tambin
Gua de programacin de C#
Clases y estructuras
Structs
Herencia (Gua de programacin de C#)
03/10/2017 7 min to read Edit Online

La herencia, junto con la encapsulacin y el polimorfismo, es una de las tres caractersticas principales de la
programacin orientada a objetos. La herencia permite crear clases nuevas que reutilizan, extienden y modifican
el comportamiento que se define en otras clases. La clase cuyos miembros se heredan se denomina clase base y
la clase que hereda esos miembros se denomina clase derivada. Una clase derivada solo puede tener una clase
base directa, pero la herencia es transitiva. Si ClaseC se deriva de ClaseB y ClaseB se deriva de ClaseA, ClaseC
hereda los miembros declarados en ClaseB y ClaseA.

NOTA
Los structs no admiten la herencia, pero pueden implementar interfaces. Para obtener ms informacin, vea Interfaces.

Conceptualmente, una clase derivada es una especializacin de la clase base. Por ejemplo, si tiene una clase base
Animal , podra tener una clase derivada denominada Mammal y otra clase derivada denominada Reptile .
Mammal es Animal y Reptile tambin es Animal , pero cada clase derivada representa especializaciones
diferentes de la clase base.
Cuando se define una clase para que derive de otra clase, la clase derivada obtiene implcitamente todos los
miembros de la clase base, salvo sus constructores y sus finalizadores. La clase derivada puede reutilizar el cdigo
de la clase base sin tener que volver a implementarlo. Puede agregar ms miembros en la clase derivada. De esta
manera, la clase derivada ampla la funcionalidad de la clase base.
En la ilustracin siguiente se muestra una clase WorkItem que representa un elemento de trabajo de un proceso
empresarial. Como con todas las clases, se deriva de System.Object y hereda todos sus mtodos. WorkItem
agrega cinco miembros propios. Entre estos se incluye un constructor, dado que los constructores no se heredan.
La clase ChangeRequest hereda de WorkItem y representa un tipo concreto de elemento de trabajo. ChangeRequest
agrega dos miembros ms a los miembros que hereda de WorkItem y de Object. Debe agregar su propio
constructor y adems agrega originalItemID . La propiedad originalItemID permite que la instancia
ChangeRequest se asocie con el WorkItem original al que se aplica la solicitud de cambio.

Herencia de clases
En el ejemplo siguiente se muestra cmo se expresan en C# las relaciones de clase de la ilustracin anterior. En el
ejemplo tambin se muestra cmo WorkItem reemplaza el mtodo virtual Object.ToString y cmo la clase
ChangeRequest hereda la implementacin WorkItem del mtodo.
// WorkItem implicitly inherits from the Object class.
public class WorkItem
{
// Static field currentID stores the job ID of the last WorkItem that
// has been created.
private static int currentID;

//Properties.
protected int ID { get; set; }
protected string Title { get; set; }
protected string Description { get; set; }
protected TimeSpan jobLength { get; set; }

// Default constructor. If a derived class does not invoke a base-


// class constructor explicitly, the default constructor is called
// implicitly.
public WorkItem()
{
ID = 0;
Title = "Default title";
Description = "Default description.";
jobLength = new TimeSpan();
}

// Instance constructor that has three parameters.


public WorkItem(string title, string desc, TimeSpan joblen)
{
this.ID = GetNextID();
this.Title = title;
this.Description = desc;
this.jobLength = joblen;
}

// Static constructor to initialize the static member, currentID. This


// constructor is called one time, automatically, before any instance
// of WorkItem or ChangeRequest is created, or currentID is referenced.
static WorkItem()
{
currentID = 0;
}

protected int GetNextID()


{
// currentID is a static field. It is incremented each time a new
// instance of WorkItem is created.
return ++currentID;
}

// Method Update enables you to update the title and job length of an
// existing WorkItem object.
public void Update(string title, TimeSpan joblen)
{
this.Title = title;
this.jobLength = joblen;
}

// Virtual method override of the ToString method that is inherited


// from System.Object.
public override string ToString()
{
return String.Format("{0} - {1}", this.ID, this.Title);
}
}

// ChangeRequest derives from WorkItem and adds a property (originalItemID)


// and two constructors.
public class ChangeRequest : WorkItem
{
protected int originalItemID { get; set; }

// Constructors. Because neither constructor calls a base-class


// constructor explicitly, the default constructor in the base class
// is called implicitly. The base class must contain a default
// constructor.

// Default constructor for the derived class.


public ChangeRequest() { }

// Instance constructor that has four parameters.


public ChangeRequest(string title, string desc, TimeSpan jobLen,
int originalID)
{
// The following properties and the GetNexID method are inherited
// from WorkItem.
this.ID = GetNextID();
this.Title = title;
this.Description = desc;
this.jobLength = jobLen;

// Property originalItemId is a member of ChangeRequest, but not


// of WorkItem.
this.originalItemID = originalID;
}
}

class Program
{
static void Main()
{
// Create an instance of WorkItem by using the constructor in the
// base class that takes three arguments.
WorkItem item = new WorkItem("Fix Bugs",
"Fix all bugs in my code branch",
new TimeSpan(3, 4, 0, 0));

// Create an instance of ChangeRequest by using the constructor in


// the derived class that takes four arguments.
ChangeRequest change = new ChangeRequest("Change Base Class Design",
"Add members to the class",
new TimeSpan(4, 0, 0),
1);

// Use the ToString method defined in WorkItem.


Console.WriteLine(item.ToString());

// Use the inherited Update method to change the title of the


// ChangeRequest object.
change.Update("Change the Design of the Base Class",
new TimeSpan(4, 0, 0));

// ChangeRequest inherits WorkItem's override of ToString.


Console.WriteLine(change.ToString());

// Keep the console open in debug mode.


Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
/* Output:
1 - Fix Bugs
2 - Change the Design of the Base Class
*/
Mtodos abstractos y virtuales
Cuando una clase base declara un mtodo como virtual, una clase derivada puede reemplazar el mtodo con su
propia implementacin. Si una clase base declara un miembro como abstracto, ese mtodo se debe reemplazar
en todas las clases no abstractas que hereden directamente de dicha clase. Si una clase derivada es abstracta,
hereda los miembros abstractos sin implementarlos. Los miembros abstractos y virtuales son la base del
polimorfismo, que es la segunda caracterstica principal de la programacin orientada a objetos. Para obtener
ms informacin, vea Polimorfismo .

Clases base abstractas


Puede declarar una clase como abstracta para quiere impedir la creacin directa de instancias mediante la palabra
clave new. Si lo hace, la clase solo se puede usar si se deriva de ella una clase nueva. Una clase abstracta puede
contener una o ms firmas de mtodo que, a su vez, se declaran como abstractas. Estas firmas especifican los
parmetros y el valor devuelto, pero no tienen ninguna implementacin (cuerpo del mtodo). Una clase abstracta
no tiene que contener miembros abstractos, pero si lo hace, la clase debe declararse como abstracta. Las clases
derivadas que no son abstractas deben proporcionar la implementacin para todos los mtodos abstractos de
una clase base abstracta. Para obtener ms informacin, vea Clases y miembros de clase abstractos y sellados.

Interfaces
Una interfaz es un tipo de referencia similar a una clase base abstracta formada nicamente por miembros
abstractos. Cuando una clase implementa una interfaz, debe proporcionar una implementacin para todos los
miembros de la interfaz. Una clase puede implementar varias interfaces, aunque solo puede derivar de una nica
clase base directa.
Las interfaces se usan para definir funciones especficas para clases que no tienen necesariamente una relacin
"es un/una". Por ejemplo, la interfaz System.IEquatable<T> se puede implementar mediante cualquier clase o
struct que deba permitir que el cdigo de cliente determine si dos objetos del tipo son equivalentes (pero el tipo
define la equivalencia). IEquatable<T> no implica el mismo tipo de relacin "es un/una" que existe entre una clase
base y una clase derivada (por ejemplo, Mammal es Animal ). Para ms informacin, vea Interfaces.

Impedir la derivacin adicional


Una clase puede impedir que otras clases hereden de ella o de cualquiera de sus miembros. Para ello, se declara a
s misma o declara su miembro como sellado. Para obtener ms informacin, vea Clases y miembros de clase
abstractos y sellados.

Clase derivada que oculta miembros de clase base


Una clase derivada puede ocultar miembros de clase base si declara los miembros con el mismo nombre y firma.
Se puede usar el modificador new para indicar explcitamente que el miembro no est diseado para reemplazar
al miembro base. No es necesario usar new, pero se generar una advertencia del compilador si no se usa new.
Para obtener ms informacin, vea Control de versiones con las palabras clave Override y New y Saber cundo
usar las palabras clave Override y New.

Vea tambin
Gua de programacin de C#
Clases y structs
class
struct
Polimorfismo (Gua de programacin de C#)
03/10/2017 8 min to read Edit Online

El polimorfismo suele considerarse el tercer pilar de la programacin orientada a objetos, despus de la


encapsulacin y la herencia. Polimorfismo es una palabra griega que significa "con muchas formas" y tiene dos
aspectos diferentes:
En tiempo de ejecucin, los objetos de una clase derivada pueden ser tratados como objetos de una clase
base en lugares como parmetros de mtodos y colecciones o matrices. Cuando ocurre, el tipo declarado
del objeto ya no es idntico a su tipo en tiempo de ejecucin.
Las clases base pueden definir e implementar mtodos virtuales, y las clases derivadas pueden invalidarlos,
lo que significa que pueden proporcionar su propia definicin e implementacin. En tiempo de ejecucin,
cuando el cdigo de cliente llama al mtodo, CLR busca el tipo en tiempo de ejecucin del objeto e invoca
esa invalidacin del mtodo virtual. Por lo tanto, en el cdigo fuente puede llamar a un mtodo en una clase
base y hacer que se ejecute una versin del mtodo de la clase derivada.
Los mtodos virtuales permiten trabajar con grupos de objetos relacionados de manera uniforme. Por ejemplo,
supongamos que tiene una aplicacin de dibujo que permite a un usuario crear varios tipos de formas en una
superficie de dibujo. En tiempo de compilacin, no sabe qu tipos especficos de formas crear el usuario. Sin
embargo, la aplicacin tiene que realizar el seguimiento de los distintos tipos de formas que se crean, y tiene que
actualizarlos en respuesta a las acciones del mouse del usuario. Para solucionar este problema en dos pasos
bsicos, puede usar el polimorfismo:
1. Crear una jerarqua de clases en la que cada clase de forma especfica deriva de una clase base comn.
2. Usar un mtodo virtual para invocar el mtodo apropiado en una clase derivada mediante una sola llamada
al mtodo de la clase base.
Primero, cree una clase base llamada Shape y clases derivadas como Rectangle , Circle y Triangle . D a la clase
Shape un mtodo virtual llamado Draw e invaldelo en cada clase derivada para dibujar la forma determinada que
la clase representa. Cree un objeto List<Shape> y agregue Circle, Triangle y Rectangle a l. Para actualizar la
superficie de dibujo, use un bucle foreach para iterar por la lista y llamar al mtodo Draw en cada objeto Shape de
la lista. Aunque cada objeto de la lista tenga un tipo declarado de Shape , se invocar el tipo en tiempo de
ejecucin (la versin invalidada del mtodo en cada clase derivada).

using System;
using System.Collections.Generic;

public class Shape


{
// A few example members
public int X { get; private set; }
public int Y { get; private set; }
public int Height { get; set; }
public int Width { get; set; }

// Virtual method
public virtual void Draw()
{
Console.WriteLine("Performing base class drawing tasks");
}
}

class Circle : Shape


{
{
public override void Draw()
{
// Code to draw a circle...
Console.WriteLine("Drawing a circle");
base.Draw();
}
}
class Rectangle : Shape
{
public override void Draw()
{
// Code to draw a rectangle...
Console.WriteLine("Drawing a rectangle");
base.Draw();
}
}
class Triangle : Shape
{
public override void Draw()
{
// Code to draw a triangle...
Console.WriteLine("Drawing a triangle");
base.Draw();
}
}

class Program
{
static void Main(string[] args)
{
// Polymorphism at work #1: a Rectangle, Triangle and Circle
// can all be used whereever a Shape is expected. No cast is
// required because an implicit conversion exists from a derived
// class to its base class.
var shapes = new List<Shape>
{
new Rectangle(),
new Triangle(),
new Circle()
};

// Polymorphism at work #2: the virtual method Draw is


// invoked on each of the derived classes, not the base class.
foreach (var shape in shapes)
{
shape.Draw();
}

// Keep the console open in debug mode.


Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}

/* Output:
Drawing a rectangle
Performing base class drawing tasks
Drawing a triangle
Performing base class drawing tasks
Drawing a circle
Performing base class drawing tasks
*/

En C#, cada tipo es polimrfico porque todos los tipos, incluidos los definidos por el usuario, heredan de Object.
Introduccin al polimorfismo
Miembros virtuales
Cuando una clase derivada hereda de una clase base, obtiene todos los mtodos, campos, propiedades y eventos
de la clase base. El diseador de la clase derivada tiene las siguientes opciones:
Invalidar los miembros virtuales de la clase base.
Heredar el mtodo de la clase base ms prximo sin invalidarlo.
Definir una nueva implementacin no virtual de esos miembros que oculte las implementaciones de la clase
base.
Una clase derivada puede invalidar un miembro de la clase base si este se declara como virtual o abstracto. El
miembro derivado debe usar la palabra clave override para indicar explcitamente que el propsito del mtodo es
participar en una invocacin virtual. El siguiente fragmento de cdigo muestra un ejemplo:

public class BaseClass


{
public virtual void DoWork() { }
public virtual int WorkProperty
{
get { return 0; }
}
}
public class DerivedClass : BaseClass
{
public override void DoWork() { }
public override int WorkProperty
{
get { return 0; }
}
}

Los campos no pueden ser virtuales; solo los mtodos, propiedades, eventos e indizadores pueden ser virtuales.
Cuando una clase derivada invalida un miembro virtual, se llama a ese miembro aunque se acceda a una instancia
de esa clase como una instancia de la clase base. El siguiente fragmento de cdigo muestra un ejemplo:

DerivedClass B = new DerivedClass();


B.DoWork(); // Calls the new method.

BaseClass A = (BaseClass)B;
A.DoWork(); // Also calls the new method.

Los mtodos y propiedades virtuales permiten a las clases derivadas extender una clase base sin necesidad de usar
la implementacin de clase base de un mtodo. Para obtener ms informacin, consulte Control de versiones con
las palabras clave Override y New. Una interfaz proporciona otra manera de definir un mtodo o conjunto de
mtodos cuya implementacin se deja a las clases derivadas. Para obtener ms informacin, vea Interfaces.
Ocultar miembros de clase base con nuevos miembros
Si quiere que el miembro derivado tenga el mismo nombre que un miembro de una clase base, pero no quiere
que participe en la invocacin virtual, puede usar la palabra clave new. La palabra clave new se coloca antes que el
tipo devuelto del miembro de la clase que se est reemplazando. El siguiente fragmento de cdigo muestra un
ejemplo:
public class BaseClass
{
public void DoWork() { WorkField++; }
public int WorkField;
public int WorkProperty
{
get { return 0; }
}
}

public class DerivedClass : BaseClass


{
public new void DoWork() { WorkField++; }
public new int WorkField;
public new int WorkProperty
{
get { return 0; }
}
}

An se puede acceder a los miembros de la clase base ocultos desde el cdigo de cliente convirtiendo la instancia
de la clase derivada en una instancia de la clase base. Por ejemplo:

DerivedClass B = new DerivedClass();


B.DoWork(); // Calls the new method.

BaseClass A = (BaseClass)B;
A.DoWork(); // Calls the old method.

Evitar que las clases derivadas invaliden los miembros virtuales


Los miembros virtuales permanecen virtuales indefinidamente, independientemente de cuntas clases se hayan
declarado entre el miembro virtual y la clase que originalmente la declar. Si la clase A declara un miembro virtual
y la clase B deriva de A, y la clase C deriva de B, la clase C hereda el miembro virtual y tiene la opcin de
invalidarlo, independientemente de que la clase B declarara una invalidacin para ese miembro. El siguiente
fragmento de cdigo muestra un ejemplo:

public class A
{
public virtual void DoWork() { }
}
public class B : A
{
public override void DoWork() { }
}

Una clase derivada puede detener la herencia virtual al declarar una invalidacin como sealed. Para ello, es
necesario colocar la palabra clave sealed antes de la palabra clave override en la declaracin del miembro de la
clase. El siguiente fragmento de cdigo muestra un ejemplo:

public class C : B
{
public sealed override void DoWork() { }
}

En el ejemplo anterior, el mtodo DoWork ya no es virtual para ninguna clase que derive de C. Sigue siendo virtual
para instancias de C, aunque se conviertan al tipo B o A. Los mtodos sellados pueden reemplazarse por las clases
derivadas al usar la palabra clave new , como se muestra en el ejemplo siguiente:
public class D : C
{
public new void DoWork() { }
}

En este caso, si se llama a DoWork en D usando una variable de tipo D, se llama al nuevo DoWork . Si se usa una
variable de tipo C, B o A para acceder a una instancia de D, la llamada a DoWork seguir las reglas de herencia
virtual y enrutar dichas llamadas a la implementacin de DoWork en la clase C.
Acceder a miembros virtuales de clases base desde clases derivadas
Una clase derivada que ha reemplazado o invalidado un mtodo o propiedad puede seguir accediendo al mtodo
o propiedad en la clase base usando la siguiente palabra clave base. El siguiente fragmento de cdigo muestra un
ejemplo:

public class Base


{
public virtual void DoWork() {/*...*/ }
}
public class Derived : Base
{
public override void DoWork()
{
//Perform Derived's work here
//...
// Call DoWork on base class
base.DoWork();
}
}

Para obtener ms informacin, vea base.

NOTA
Se recomienda que las mquinas virtuales usen base para llamar a la implementacin de la clase base de ese miembro en
su propia implementacin. Dejar que se produzca el comportamiento de la clase base permite a la clase derivada
concentrarse en implementar el comportamiento especfico de la clase derivada. Si no se llama a la implementacin de la
clase base, depende de la clase derivada hacer que su comportamiento sea compatible con el de la clase base.

En esta seccin
Control de versiones con las palabras clave Override y New
Saber cundo utilizar las palabras clave Override y New
Cmo: Invalidar el mtodo ToString

Vea tambin
Gua de programacin de C#
Gua de programacin de C#
Herencia
Clases y miembros de clase abstractos y sellados
Mtodos
Eventos
Propiedades
Indexers (Indexadores)
Tipos
Control de versiones con las palabras clave Override
y New (Gua de programacin de C#)
03/10/2017 5 min to read Edit Online

El lenguaje C# est diseado para que las versiones entre clases base y derivadas de diferentes bibliotecas puedan
evolucionar y mantener la compatibilidad con versiones anteriores. Esto significa, por ejemplo, que la introduccin
de un nuevo miembro en una clase base con el mismo nombre que un miembro de una clase derivada es
totalmente compatible con C# y no lleva a un comportamiento inesperado. Adems, implica que una clase debe
declarar explcitamente si un mtodo est pensado para reemplazar un mtodo heredado o si se trata de un nuevo
mtodo que oculta un mtodo heredado de nombre similar.
En C#, las clases derivadas pueden contener mtodos con el mismo nombre que los mtodos de clase base.
El mtodo de clase base debe definirse como virtual.
Si el mtodo de la clase derivada no va precedido por las palabras clave new u override, el compilador
emite una advertencia y el mtodo se comporta como si la palabra clave new estuviese presente.
Si el mtodo de la clase derivada va precedido de la palabra clave new , el mtodo se define como
independiente del mtodo de la clase base.
Si el mtodo de la clase derivada va precedido de la palabra clave override , los objetos de la clase derivada
llamarn a ese mtodo y no al mtodo de la clase base.
El mtodo de clase base puede llamarse desde dentro de la clase derivada mediante la palabra clave base .
Las palabras clave override , virtual y new tambin pueden aplicarse a propiedades, indexadores y
eventos.
De forma predeterminada, los mtodos de C# no son virtuales. Si se declara un mtodo como virtual, toda clase
que hereda el mtodo puede implementar su propia versin Para que un mtodo sea virtual, se usa el modificador
virtual en la declaracin del mtodo de la clase base. La clase derivada puede luego reemplazar el mtodo base
virtual mediante la palabra clave override u ocultar el mtodo virtual en la clase base mediante la palabra clave
new . Si no se especifican las palabras clave override o new , el compilador emite una advertencia y el mtodo de
la clase derivada oculta el mtodo de la clase base.
Para demostrar esto en la prctica, supongamos por un momento que la compaa A ha creado una clase
denominada GraphicsClass , que su programa usa. La siguiente es GraphicsClass :

class GraphicsClass
{
public virtual void DrawLine() { }
public virtual void DrawPoint() { }
}

Su compaa usa esta clase y usted la usa para derivar su propia clase, agregando un nuevo mtodo:

class YourDerivedGraphicsClass : GraphicsClass


{
public void DrawRectangle() { }
}
La aplicacin se usa sin problemas, hasta que la compaa A lanza una nueva versin de GraphicsClass , que es
similar al cdigo siguiente:

class GraphicsClass
{
public virtual void DrawLine() { }
public virtual void DrawPoint() { }
public virtual void DrawRectangle() { }
}

La nueva versin de GraphicsClass contiene ahora un mtodo denominado DrawRectangle . Inicialmente, no


sucede nada. La nueva versin sigue siendo compatible a nivel binario con la versin anterior. Cualquier software
que haya implementado seguir funcionando, aunque la nueva clase se instale en esos sistemas informticos.
Cualquier llamada existente al mtodo DrawRectangle seguir haciendo referencia a su versin en la clase
derivada.
Pero en cuanto vuelva a compilar la aplicacin con la nueva versin de GraphicsClass , recibir una advertencia del
compilador, CS0108. Esta advertencia le informa de que debe plantearse cmo quiere que el mtodo
DrawRectangle se comporte en la aplicacin.

Si quiere que su mtodo reemplace al nuevo mtodo de clase base, use la palabra clave override :

class YourDerivedGraphicsClass : GraphicsClass


{
public override void DrawRectangle() { }
}

La palabra clave override se asegura de que los objetos derivados de YourDerivedGraphicsClass usen la versin
de la clase derivada de DrawRectangle . Los objetos derivados de YourDerivedGraphicsClass todava pueden
acceder a la versin de clase base DrawRectangle mediante la palabra clave base:

base.DrawRectangle();

Si no quiere que el mtodo reemplace al nuevo mtodo de clase base, se aplican las consideraciones siguientes.
Para evitar la confusin entre los dos mtodos, puede cambiarle el nombre a su mtodo. Esto puede ser un
proceso lento y propenso a errores y no resultar prctico en algunos casos. Pero si el proyecto es relativamente
pequeo, puede usar opciones de refactorizacin de Visual Studio para cambiar el nombre del mtodo. Para
obtener ms informacin, vea Refactoring Classes and Types (Class Designer) (Refactorizacin de clases y tipos
[Diseador de clases]).
Tambin puede evitar la advertencia mediante la palabra clave new en la definicin de clase derivada:

class YourDerivedGraphicsClass : GraphicsClass


{
public new void DrawRectangle() { }
}

Con la palabra clave new se indica al compilador que su definicin oculta la definicin contenida en la clase base.
ste es el comportamiento predeterminado.

Seleccin de mtodo y reemplazo


Cuando se llama a un mtodo en una clase, el compilador de C# selecciona el mejor mtodo para llamar si hay
ms de uno compatible con la llamada, como cuando hay dos mtodos con el mismo nombre y parmetros que
son compatibles con el parmetro pasado. Los mtodos siguientes seran compatibles:

public class Derived : Base


{
public override void DoWork(int param) { }
public void DoWork(double param) { }
}

Cuando se llama a DoWork en una instancia de Derived , el compilador de C# intentar en primer lugar que la
llamada sea compatible con las versiones de DoWork declaradas originalmente en Derived . Los mtodos de
reemplazo no se consideran como declarados en una clase, son nuevas implementaciones de un mtodo que se
declara en una clase base. Solo si el compilador de C# no puede hacer coincidir la llamada al mtodo con un
mtodo original en Derived , intentar hacer coincidir la llamada con un mtodo reemplazado con el mismo
nombre y parmetros compatibles. Por ejemplo:

int val = 5;
Derived d = new Derived();
d.DoWork(val); // Calls DoWork(double).

Dado que la variable val se puede convertir implcitamente en un valor doble, el compilador de C# llama a
DoWork(double) en lugar de a DoWork(int) . Hay dos maneras de evitarlo. En primer lugar, evite declarar nuevos
mtodos con el mismo nombre que los mtodos virtuales. En segundo lugar, puede indicar al compilador de C#
que llame al mtodo virtual haciendo que busque la lista de mtodos de clase base mediante la conversin de la
instancia de Derived a Base . Como el mtodo es virtual, se llamar a la implementacin de DoWork(int) en
Derived . Por ejemplo:

((Base)d).DoWork(val); // Calls DoWork(int) on Derived.

Para obtener otros ejemplos de new y override , vea Knowing When to Use Override and New Keywords (Saber
cundo usar las palabras clave override y new [Gua de programacin de C#]).

Vea tambin
Gua de programacin de C#
Clases y estructuras
Methods (Mtodos [Gua de programacin de C#])
Herencia
Saber cundo utilizar las palabras clave Override y
New (Gua de programacin de C#)
03/10/2017 11 min to read Edit Online

En C#, un mtodo de una clase derivada puede tener el mismo nombre que un mtodo de la clase base. Se puede
especificar cmo interactan los mtodos mediante las palabras clave new y override. El modificador override
extiende el mtodo de clase base y el modificador new lo oculta. En los ejemplos de este tema se ilustra la
diferencia.
En una aplicacin de consola, declare las dos clases siguientes, BaseClass y DerivedClass . DerivedClass hereda
de BaseClass .

class BaseClass
{
public void Method1()
{
Console.WriteLine("Base - Method1");
}
}

class DerivedClass : BaseClass


{
public void Method2()
{
Console.WriteLine("Derived - Method2");
}
}

En el mtodo Main , declare las variables bc , dc y bcdc .


bc es de tipo BaseClass , y su valor es de tipo BaseClass .
dc es de tipo DerivedClass , y su valor es de tipo DerivedClass .
bcdc es de tipo BaseClass , y su valor es de tipo DerivedClass . Esta es la variable a la que hay que prestar
atencin.
Dado que bc y bcdc tienen el tipo BaseClass , solo pueden tener acceso directo a Method1 , a menos que se use
la conversin. La variable dc puede tener acceso a Method1 y Method2 . Estas relaciones se muestran en el cdigo
siguiente.
class Program
{
static void Main(string[] args)
{
BaseClass bc = new BaseClass();
DerivedClass dc = new DerivedClass();
BaseClass bcdc = new DerivedClass();

bc.Method1();
dc.Method1();
dc.Method2();
bcdc.Method1();
}
// Output:
// Base - Method1
// Base - Method1
// Derived - Method2
// Base - Method1
}

Despus, agregue el mtodo Method2 siguiente a BaseClass . La firma de este mtodo coincide con la firma del
mtodo Method2 de DerivedClass .

public void Method2()


{
Console.WriteLine("Base - Method2");
}

Dado que BaseClass ahora tiene un mtodo Method2 , se puede agregar una segunda instruccin de llamada para
las variables de BaseClass bc y bcdc , como se muestra en el cdigo siguiente.

bc.Method1();
bc.Method2();
dc.Method1();
dc.Method2();
bcdc.Method1();
bcdc.Method2();

Al compilar el proyecto, ver que la adicin del mtodo Method2 de BaseClass genera una advertencia. La
advertencia indica que el mtodo Method2 de DerivedClass oculta el mtodo Method2 de BaseClass . Se
recomienda usar la palabra clave new en la definicin de Method2 si se pretende provocar ese resultado. Como
alternativa, se puede cambiar el nombre de uno de los mtodos Method2 para resolver la advertencia, pero eso no
siempre resulta prctico.
Antes de agregar new , ejecute el programa para ver el resultado producido por las instrucciones adicionales que
realizan la llamada. Se muestran los resultados siguientes.

// Output:
// Base - Method1
// Base - Method2
// Base - Method1
// Derived - Method2
// Base - Method1
// Base - Method2

La palabra clave new conserva las relaciones que generan ese resultado, pero se suprime la advertencia. Las
variables de tipo BaseClass siguen teniendo acceso a los miembros de BaseClass y la variable de tipo
DerivedClass sigue teniendo acceso a los miembros de DerivedClass en primer lugar y, despus, tiene en cuenta
los miembros heredados de BaseClass .
Para suprimir la advertencia, agregue el modificador new a la definicin de Method2 en DerivedClass , como se
muestra en el cdigo siguiente. Se puede agregar el modificador antes o despus de public .

public new void Method2()


{
Console.WriteLine("Derived - Method2");
}

Vuelva a ejecutar el programa para comprobar que el resultado no ha cambiado. Compruebe tambin que ya no
aparece la advertencia. Mediante el uso de new , afirma que es consciente de que el miembro que modifica oculta
un miembro heredado de la clase base. Para ms informacin sobre la ocultacin de nombres a travs de la
herencia, vea new (Modificador, Referencia de C#).
Para contrastar este comportamiento con los efectos de usar override , agregue el mtodo siguiente a
DerivedClass . Se puede agregar el modificador override antes o despus de public .

public override void Method1()


{
Console.WriteLine("Derived - Method1");
}

Agregue el modificador virtual a la definicin de Method1 en BaseClass . Se puede agregar el modificador


virtual antes o despus de public .

public virtual void Method1()


{
Console.WriteLine("Base - Method1");
}

Vuelva a ejecutar el proyecto. Observe especialmente las dos ltimas lneas del resultado siguiente.

// Output:
// Base - Method1
// Base - Method2
// Derived - Method1
// Derived - Method2
// Derived - Method1
// Base - Method2

El uso del modificador override permite que bcdc tenga acceso al mtodo Method1 que se define en
DerivedClass . Normalmente, es el comportamiento deseado en jerarquas de herencia. La intencin es que los
objetos que tienen valores que se crean a partir de la clase derivada usen los mtodos que se definen en la clase
derivada. Ese comportamiento se consigue mediante el uso de override para extender el mtodo de clase base.
El cdigo siguiente contiene el ejemplo completo.
using System;
using System.Text;

namespace OverrideAndNew
{
class Program
{
static void Main(string[] args)
{
BaseClass bc = new BaseClass();
DerivedClass dc = new DerivedClass();
BaseClass bcdc = new DerivedClass();

// The following two calls do what you would expect. They call
// the methods that are defined in BaseClass.
bc.Method1();
bc.Method2();
// Output:
// Base - Method1
// Base - Method2

// The following two calls do what you would expect. They call
// the methods that are defined in DerivedClass.
dc.Method1();
dc.Method2();
// Output:
// Derived - Method1
// Derived - Method2

// The following two calls produce different results, depending


// on whether override (Method1) or new (Method2) is used.
bcdc.Method1();
bcdc.Method2();
// Output:
// Derived - Method1
// Base - Method2
}
}

class BaseClass
{
public virtual void Method1()
{
Console.WriteLine("Base - Method1");
}

public virtual void Method2()


{
Console.WriteLine("Base - Method2");
}
}

class DerivedClass : BaseClass


{
public override void Method1()
{
Console.WriteLine("Derived - Method1");
}

public new void Method2()


{
Console.WriteLine("Derived - Method2");
}
}
}
En el ejemplo siguiente se muestra un comportamiento similar en un contexto diferente. El ejemplo define tres
clases: una clase base denominada Car y dos clases que se derivan de ella, ConvertibleCar y Minivan . La clase
base contiene un mtodo DescribeCar . El mtodo muestra una descripcin bsica de un automvil y, despus,
llama a ShowDetails para proporcionar informacin adicional. Cada una de las tres clases define un mtodo
ShowDetails . El modificador new se usa para definir ShowDetails en la clase ConvertibleCar . El modificador
override se usa para definir ShowDetails en la clase Minivan .

// Define the base class, Car. The class defines two methods,
// DescribeCar and ShowDetails. DescribeCar calls ShowDetails, and each derived
// class also defines a ShowDetails method. The example tests which version of
// ShowDetails is selected, the base class method or the derived class method.
class Car
{
public void DescribeCar()
{
System.Console.WriteLine("Four wheels and an engine.");
ShowDetails();
}

public virtual void ShowDetails()


{
System.Console.WriteLine("Standard transportation.");
}
}

// Define the derived classes.

// Class ConvertibleCar uses the new modifier to acknowledge that ShowDetails


// hides the base class method.
class ConvertibleCar : Car
{
public new void ShowDetails()
{
System.Console.WriteLine("A roof that opens up.");
}
}

// Class Minivan uses the override modifier to specify that ShowDetails


// extends the base class method.
class Minivan : Car
{
public override void ShowDetails()
{
System.Console.WriteLine("Carries seven people.");
}
}

El ejemplo comprueba la versin de ShowDetails que se llama. El siguiente mtodo, TestCars1 , declara una
instancia de cada clase y, despus, llama a DescribeCar en cada instancia.
public static void TestCars1()
{
System.Console.WriteLine("\nTestCars1");
System.Console.WriteLine("----------");

Car car1 = new Car();


car1.DescribeCar();
System.Console.WriteLine("----------");

// Notice the output from this test case. The new modifier is
// used in the definition of ShowDetails in the ConvertibleCar
// class.

ConvertibleCar car2 = new ConvertibleCar();


car2.DescribeCar();
System.Console.WriteLine("----------");

Minivan car3 = new Minivan();


car3.DescribeCar();
System.Console.WriteLine("----------");
}

TestCars1 genera el siguiente resultado. Observe especialmente los resultados de car2 , que probablemente no
son los que se esperaban. El tipo de objeto es ConvertibleCar , pero DescribeCar no tiene acceso a la versin de
ShowDetails que se define en la clase ConvertibleCar porque ese mtodo se declara con el modificador new , no
con el modificador override . Como resultado, un objeto ConvertibleCar muestra la misma descripcin que un
objeto Car . Compare los resultados de car3 , que es un objeto Minivan . En este caso, el mtodo ShowDetails
que se declara en la clase Minivan invalida el mtodo ShowDetails que se declara en la clase Car , y en la
descripcin que se muestra se describe una furgoneta.

// TestCars1
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Carries seven people.
// ----------

TestCars2 crea una lista de objetos que tienen el tipo Car . Se crean instancias de los valores de los objetos desde
las clases Car , ConvertibleCar y Minivan . DescribeCar se llama en cada elemento de la lista. En el cdigo
siguiente se muestra la definicin de TestCars2 .

public static void TestCars2()


{
System.Console.WriteLine("\nTestCars2");
System.Console.WriteLine("----------");

var cars = new List<Car> { new Car(), new ConvertibleCar(),


new Minivan() };

foreach (var car in cars)


{
car.DescribeCar();
System.Console.WriteLine("----------");
}
}
Se muestra el siguiente resultado. Observe que es el mismo resultado mostrado por TestCars1 . El mtodo
ShowDetails de la clase ConvertibleCar no se llama, independientemente de si el tipo de objeto es
ConvertibleCar , como en TestCars1 , o Car como en TestCars2 . Por el contrario, car3 llama al mtodo
ShowDetails desde la clase Minivan en ambos casos, independientemente de que tenga el tipo Minivan o Car .

// TestCars2
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Carries seven people.
// ----------

Los mtodos TestCars3 y TestCars4 completan el ejemplo. Estos mtodos llaman directamente a ShowDetails ,
primero desde los objetos declarados con el tipo ConvertibleCar y Minivan ( TestCars3 ), y despus desde los
objetos declarados con el tipo Car ( TestCars4 ). En el cdigo siguiente se definen estos dos mtodos.

public static void TestCars3()


{
System.Console.WriteLine("\nTestCars3");
System.Console.WriteLine("----------");
ConvertibleCar car2 = new ConvertibleCar();
Minivan car3 = new Minivan();
car2.ShowDetails();
car3.ShowDetails();
}

public static void TestCars4()


{
System.Console.WriteLine("\nTestCars4");
System.Console.WriteLine("----------");
Car car2 = new ConvertibleCar();
Car car3 = new Minivan();
car2.ShowDetails();
car3.ShowDetails();
}

Los mtodos generan el siguiente resultado, que se corresponde a los resultados del primer ejemplo de este tema.

// TestCars3
// ----------
// A roof that opens up.
// Carries seven people.

// TestCars4
// ----------
// Standard transportation.
// Carries seven people.

En el cdigo siguiente se muestra el proyecto completo y sus resultados.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace OverrideAndNew2
namespace OverrideAndNew2
{
class Program
{
static void Main(string[] args)
{
// Declare objects of the derived classes and test which version
// of ShowDetails is run, base or derived.
TestCars1();

// Declare objects of the base class, instantiated with the


// derived classes, and repeat the tests.
TestCars2();

// Declare objects of the derived classes and call ShowDetails


// directly.
TestCars3();

// Declare objects of the base class, instantiated with the


// derived classes, and repeat the tests.
TestCars4();
}

public static void TestCars1()


{
System.Console.WriteLine("\nTestCars1");
System.Console.WriteLine("----------");

Car car1 = new Car();


car1.DescribeCar();
System.Console.WriteLine("----------");

// Notice the output from this test case. The new modifier is
// used in the definition of ShowDetails in the ConvertibleCar
// class.
ConvertibleCar car2 = new ConvertibleCar();
car2.DescribeCar();
System.Console.WriteLine("----------");

Minivan car3 = new Minivan();


car3.DescribeCar();
System.Console.WriteLine("----------");
}
// Output:
// TestCars1
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Carries seven people.
// ----------

public static void TestCars2()


{
System.Console.WriteLine("\nTestCars2");
System.Console.WriteLine("----------");

var cars = new List<Car> { new Car(), new ConvertibleCar(),


new Minivan() };

foreach (var car in cars)


{
car.DescribeCar();
System.Console.WriteLine("----------");
}
}
}
// Output:
// TestCars2
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Standard transportation.
// ----------
// Four wheels and an engine.
// Carries seven people.
// ----------

public static void TestCars3()


{
System.Console.WriteLine("\nTestCars3");
System.Console.WriteLine("----------");
ConvertibleCar car2 = new ConvertibleCar();
Minivan car3 = new Minivan();
car2.ShowDetails();
car3.ShowDetails();
}
// Output:
// TestCars3
// ----------
// A roof that opens up.
// Carries seven people.

public static void TestCars4()


{
System.Console.WriteLine("\nTestCars4");
System.Console.WriteLine("----------");
Car car2 = new ConvertibleCar();
Car car3 = new Minivan();
car2.ShowDetails();
car3.ShowDetails();
}
// Output:
// TestCars4
// ----------
// Standard transportation.
// Carries seven people.
}

// Define the base class, Car. The class defines two virtual methods,
// DescribeCar and ShowDetails. DescribeCar calls ShowDetails, and each derived
// class also defines a ShowDetails method. The example tests which version of
// ShowDetails is used, the base class method or the derived class method.
class Car
{
public virtual void DescribeCar()
{
System.Console.WriteLine("Four wheels and an engine.");
ShowDetails();
}

public virtual void ShowDetails()


{
System.Console.WriteLine("Standard transportation.");
}
}

// Define the derived classes.

// Class ConvertibleCar uses the new modifier to acknowledge that ShowDetails


// hides the base class method.
class ConvertibleCar : Car
{
public new void ShowDetails()
{
System.Console.WriteLine("A roof that opens up.");
}
}

// Class Minivan uses the override modifier to specify that ShowDetails


// extends the base class method.
class Minivan : Car
{
public override void ShowDetails()
{
System.Console.WriteLine("Carries seven people.");
}
}

Vea tambin
Gua de programacin de C#
Clases y estructuras
Control de versiones con las palabras clave Override y New
base
abstract
Cmo: Invalidar el mtodo ToString (Gua de
programacin de C#)
03/10/2017 1 min to read Edit Online

Cada clase o struct de C# hereda implcitamente la clase Object. Por consiguiente, cada objeto de C# obtiene el
mtodo ToString, que devuelve una representacin de cadena de ese objeto. Por ejemplo, todas las variables de
tipo int tienen un mtodo ToString , que las habilita para devolver su contenido como cadena:

int x = 42;
string strx = x.ToString();
Console.WriteLine(strx);
// Output:
// 42

Cuando cree una clase o struct personalizados, debe reemplazar el mtodo ToString para proporcionar
informacin sobre el tipo al cdigo de cliente.
Para obtener informacin sobre cmo usar cadenas de formato y otros tipos de formato personalizado con el
mtodo ToString , vea Aplicar formato a tipos.

IMPORTANTE
Cuando decida qu informacin va a proporcionar a travs de este mtodo, considere si la clase o struct se va a usar alguna
vez en cdigo que no sea de confianza. Asegrese de que no proporciona informacin que pueda ser aprovechada por
cdigo malintencionado.

Para reemplazar el mtodo ToString en una clase o struct


1. Declare un mtodo ToString con los modificadores y el tipo de valor devuelto siguientes:

public override string ToString(){}

2. Implemente el mtodo para que devuelva una cadena.


En el ejemplo siguiente, se devuelve el nombre de la clase, adems de los datos especficos de una instancia
concreta de la clase.

class Person
{
public string Name { get; set; }
public int Age { get; set; }

public override string ToString()


{
return "Person: " + Name + " " + Age;
}
}

Se puede probar el mtodo ToString tal y como se muestra en el siguiente ejemplo de cdigo:
Person person = new Person { Name = "John", Age = 12 };
Console.WriteLine(person);
// Output:
// Person: John 12

Vea tambin
IFormattable
Gua de programacin de C#
Clases y estructuras
Cadenas
string
new
override
virtual
Aplicacin de formato a tipos
Clases y miembros de clase abstractos y sellados
(Gua de programacin de C#)
03/10/2017 2 min to read Edit Online

La palabra clave abstract permite crear clases y miembros class que estn incompletos y se deben implementar
en una clase derivada.
La palabra clave sealed permite impedir la herencia de una clase o de ciertos miembros de clase marcados
previamente como virtual.

Clases y miembros de clase abstractos


Las clases se pueden declarar como abstractas si se incluye la palabra clave abstract antes de la definicin de
clase. Por ejemplo:

public abstract class A


{
// Class members here.
}

No se pueden crear instancias de una clase abstracta. El propsito de una clase abstracta es proporcionar una
definicin comn de una clase base que mltiples clases derivadas pueden compartir. Por ejemplo, una biblioteca
de clases puede definir una clase abstracta que se utiliza como parmetro para muchas de sus funciones y
solicitar a los programadores que utilizan esa biblioteca que proporcionen su propia implementacin de la clase
mediante la creacin de una clase derivada.
Las clases abstractas tambin pueden definir mtodos abstractos. Esto se consigue agregando la palabra clave
abstract antes del tipo de valor que devuelve el mtodo. Por ejemplo:

public abstract class A


{
public abstract void DoWork(int i);
}

Los mtodos abstractos no tienen ninguna implementacin, de modo que la definicin de mtodo va seguida por
un punto y coma en lugar de un bloque de mtodo normal. Las clases derivadas de la clase abstracta deben
implementar todos los mtodos abstractos. Cuando una clase abstracta hereda un mtodo virtual de una clase
base, la clase abstracta puede reemplazar el mtodo virtual con un mtodo abstracto. Por ejemplo:
// compile with: /target:library
public class D
{
public virtual void DoWork(int i)
{
// Original implementation.
}
}

public abstract class E : D


{
public abstract override void DoWork(int i);
}

public class F : E
{
public override void DoWork(int i)
{
// New implementation.
}
}

Si un mtodo virtual se declara como abstract , sigue siendo virtual para cualquier clase que herede de la clase
abstracta. Una clase que hereda un mtodo abstracto no puede tener acceso a la implementacin original del
mtodo: en el ejemplo anterior, DoWork en la clase F no puede llamar a DoWork en la clase D. De esta manera, una
clase abstracta puede exigir a las clases derivadas que proporcionen nuevas implementaciones de mtodo para
los mtodos virtuales.

Clases y miembros de clase sellados


Las clases se pueden declarar como selladas si se incluye la palabra clave sealed antes de la definicin de clase.
Por ejemplo:

public sealed class D


{
// Class members here.
}

Una clase sellada no se puede utilizar como clase base. Por esta razn, tampoco puede ser una clase abstracta. Las
clases selladas evitan la derivacin. Puesto que nunca se pueden utilizar como clase base, algunas optimizaciones
en tiempo de ejecucin pueden hacer que sea un poco ms rpido llamar a miembros de clase sellada.
Un mtodo, indizador, propiedad o evento de una clase derivada que reemplaza a un miembro virtual de la clase
base puede declarar ese miembro como sellado. Esto niega el aspecto virtual del miembro para cualquier clase
derivada adicional. Esto se logra colocando la palabra clave sealed antes de la palabra clave override en la
declaracin del miembro de clase. Por ejemplo:

public class D : C
{
public sealed override void DoWork() { }
}

Vea tambin
Gua de programacin de C#
Clases y structs
Herencia
Mtodos
Campos
Cmo: Definir propiedades abstractas
Cmo: Definir propiedades abstractas (Gua de
programacin de C#)
03/10/2017 2 min to read Edit Online

En el ejemplo siguiente se muestra cmo definir las propiedades abstract. Una declaracin de propiedad abstracta
no proporciona una implementacin de los descriptores de acceso de propiedad, declara que la clase admite
propiedades, pero deja la implementacin del descriptor de acceso a las clases derivadas. En el ejemplo siguiente
se muestra cmo implementar las propiedades abstractas heredadas de una clase base.
Este ejemplo consta de tres archivos, cada uno de los cuales se compila individualmente y se hace referencia a su
ensamblado resultante mediante la siguiente compilacin:
abstractshape.cs: la clase Shape que contiene una propiedad Area abstracta.
shapes.cs: las subclases de la clase Shape .
shapetest.cs: un programa de prueba para mostrar las reas de algunos objetos derivados de Shape .
Para compilar el ejemplo, use el siguiente comando:
csc abstractshape.cs shapes.cs shapetest.cs

Esto crear el archivo ejecutable shapetest.exe.

Ejemplo
Este archivo declara la clase Shape que contiene la propiedad Area del tipo double .
// compile with: csc /target:library abstractshape.cs
public abstract class Shape
{
private string name;

public Shape(string s)
{
// calling the set accessor of the Id property.
Id = s;
}

public string Id
{
get
{
return name;
}

set
{
name = value;
}
}

// Area is a read-only property - only a get accessor is needed:


public abstract double Area
{
get;
}

public override string ToString()


{
return Id + " Area = " + string.Format("{0:F2}", Area);
}
}

Los modificadores de la propiedad se colocan en la propia declaracin de propiedad. Por ejemplo:

public abstract double Area

Al declarar una propiedad abstracta (como Area en este ejemplo), simplemente indica qu descriptores de
acceso de propiedad estn disponibles, pero no los implementa. En este ejemplo, solo est disponible un
descriptor de acceso get, por lo que la propiedad es de solo lectura.

Ejemplo
En el siguiente cdigo se muestran tres subclases de Shape y cmo invalidan la propiedad Area para
proporcionar su propia implementacin.
// compile with: csc /target:library /reference:abstractshape.dll shapes.cs
public class Square : Shape
{
private int side;

public Square(int side, string id)


: base(id)
{
this.side = side;
}

public override double Area


{
get
{
// Given the side, return the area of a square:
return side * side;
}
}
}

public class Circle : Shape


{
private int radius;

public Circle(int radius, string id)


: base(id)
{
this.radius = radius;
}

public override double Area


{
get
{
// Given the radius, return the area of a circle:
return radius * radius * System.Math.PI;
}
}
}

public class Rectangle : Shape


{
private int width;
private int height;

public Rectangle(int width, int height, string id)


: base(id)
{
this.width = width;
this.height = height;
}

public override double Area


{
get
{
// Given the width and height, return the area of a rectangle:
return width * height;
}
}
}

Ejemplo
En el siguiente cdigo se muestra un programa de prueba que crea un nmero de objetos derivados de Shape e
imprime sus reas.

// compile with: csc /reference:abstractshape.dll;shapes.dll shapetest.cs


class TestClass
{
static void Main()
{
Shape[] shapes =
{
new Square(5, "Square #1"),
new Circle(3, "Circle #1"),
new Rectangle( 4, 5, "Rectangle #1")
};

System.Console.WriteLine("Shapes Collection");
foreach (Shape s in shapes)
{
System.Console.WriteLine(s);
}
}
}
/* Output:
Shapes Collection
Square #1 Area = 25.00
Circle #1 Area = 28.27
Rectangle #1 Area = 20.00
*/

Vea tambin
Gua de programacin de C#
Clases y structs
Clases y miembros de clase abstractos y sellados
Propiedades
Crear y utilizar ensamblados mediante la lnea de comandos
Clases estticas y sus miembros (Gua de
programacin de C#)
03/10/2017 6 min to read Edit Online

Una clase esttica es bsicamente lo mismo que una clase no esttica, con la diferencia de que no se pueden crear
instancias de una clase esttica. En otras palabras, no puede usar la palabra clave new para crear una variable del
tipo de clase. Dado que no hay ninguna variable de instancia, para tener acceso a los miembros de una clase
esttica, debe usar el nombre de la clase. Por ejemplo, si tiene una clase esttica denominada UtilityClass que
tiene un mtodo pblico denominado MethodA , llame al mtodo tal como se muestra en el ejemplo siguiente:

UtilityClass.MethodA();

Es posible usar una clase esttica como un contenedor adecuado para conjuntos de mtodos que solo funcionan
en parmetros de entrada y que no tienen que obtener ni establecer campos de instancias internas. Por ejemplo,
en la biblioteca de clases .NET Framework, la clase esttica System.Math contiene mtodos que realizan
operaciones matemticas, sin ningn requisito para almacenar o recuperar datos que sean nicos de una
instancia concreta de la clase Math. Es decir, para aplicar los miembros de la clase, debe especificar el nombre de
clase y el nombre de mtodo, como se muestra en el ejemplo siguiente.

double dub = -3.14;


Console.WriteLine(Math.Abs(dub));
Console.WriteLine(Math.Floor(dub));
Console.WriteLine(Math.Round(Math.Abs(dub)));

// Output:
// 3.14
// -4
// 3

Como sucede con todos los tipos de clase, Common Language Runtime (CLR) de .NET Framework carga la
informacin de tipo para una clase esttica cuando se carga el programa que hace referencia a la clase. El
programa no puede especificar exactamente cundo se carga la clase, pero existe la garanta de que se cargar, de
que sus campos se inicializarn y de que se llamar a su constructor esttico antes de que se haga referencia a la
clase por primera vez en el programa. Solo se llama una vez a un constructor esttico, y una clase esttica
permanece en memoria durante la vigencia del dominio de aplicacin en el que reside el programa.

NOTA
Para crear una clase no esttica que solo permita la creacin de una instancia de s misma, vea Implementing Singleton in
C# (Implementar un singleton en C#).

La siguiente lista contiene las caractersticas principales de una clase esttica:


Solo contiene miembros estticos.
No se pueden crear instancias de ella.
Est sellada.
No puede contener constructores de instancias.
Por lo tanto, crear una clase esttica es bsicamente lo mismo que crear una clase que contiene solo miembros
estticos y un constructor privado. Un constructor privado impide que se creen instancias de la clase. La ventaja
de usar una clase esttica es que el compilador puede comprobar que no se agregue accidentalmente ningn
miembro de instancia. El compilador garantizar que no se creen instancias de esta clase.
Las clases estticas estn selladas y, por lo tanto, no pueden heredarse. No pueden heredar de ninguna clase
excepto Object. Las clases estticas no pueden contener un constructor de instancias, pero pueden contener un
constructor esttico. Las clases no estticas tambin deben definir un constructor esttico si la clase contiene
miembros estticos que requieren inicializacin no trivial. Para obtener ms informacin, vea Constructores
estticos.

Ejemplo
A continuacin se muestra un ejemplo de una clase esttica que contiene dos mtodos que convierten la
temperatura de grados Celsius a grados Fahrenheit y viceversa:

public static class TemperatureConverter


{
public static double CelsiusToFahrenheit(string temperatureCelsius)
{
// Convert argument to double for calculations.
double celsius = Double.Parse(temperatureCelsius);

// Convert Celsius to Fahrenheit.


double fahrenheit = (celsius * 9 / 5) + 32;

return fahrenheit;
}

public static double FahrenheitToCelsius(string temperatureFahrenheit)


{
// Convert argument to double for calculations.
double fahrenheit = Double.Parse(temperatureFahrenheit);

// Convert Fahrenheit to Celsius.


double celsius = (fahrenheit - 32) * 5 / 9;

return celsius;
}
}

class TestTemperatureConverter
{
static void Main()
{
Console.WriteLine("Please select the convertor direction");
Console.WriteLine("1. From Celsius to Fahrenheit.");
Console.WriteLine("2. From Fahrenheit to Celsius.");
Console.Write(":");

string selection = Console.ReadLine();


double F, C = 0;

switch (selection)
{
case "1":
Console.Write("Please enter the Celsius temperature: ");
F = TemperatureConverter.CelsiusToFahrenheit(Console.ReadLine());
Console.WriteLine("Temperature in Fahrenheit: {0:F2}", F);
break;

case "2":
Console.Write("Please enter the Fahrenheit temperature: ");
C = TemperatureConverter.FahrenheitToCelsius(Console.ReadLine());
Console.WriteLine("Temperature in Celsius: {0:F2}", C);
Console.WriteLine("Temperature in Celsius: {0:F2}", C);
break;

default:
Console.WriteLine("Please select a convertor.");
break;
}

// Keep the console window open in debug mode.


Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
/* Example Output:
Please select the convertor direction
1. From Celsius to Fahrenheit.
2. From Fahrenheit to Celsius.
:2
Please enter the Fahrenheit temperature: 20
Temperature in Celsius: -6.67
Press any key to exit.
*/

Miembros estticos
Una clase no esttica puede contener mtodos, campos, propiedades o eventos estticos. El miembro esttico es
invocable en una clase, incluso si no se ha creado ninguna instancia de la clase. Siempre se tiene acceso al
miembro esttico con el nombre de clase, no con el nombre de instancia. Solo existe una copia de un miembro
esttico, independientemente del nmero de instancias de la clase que se creen. Los mtodos y las propiedades
estticos no pueden tener acceso a campos y eventos no estticos en su tipo contenedor, y tampoco pueden tener
acceso a una variable de instancia de un objeto a menos que se pase explcitamente en un parmetro de mtodo.
Es ms habitual declarar una clase no esttica con algunos miembros estticos que declarar toda una clase como
esttica. Dos usos habituales de los campos estticos son llevar la cuenta del nmero de objetos de los que se han
creado instancias y almacenar un valor que se debe compartir entre todas las instancias.
Los mtodos estticos se pueden sobrecargar pero no invalidar, ya que pertenecen a la clase y no a una instancia
de la clase.
Aunque un campo no se puede declarar como static const , el campo const es bsicamente esttico en su
comportamiento. Pertenece al tipo, no a las instancias del tipo. Por lo tanto, se puede tener acceso a campos const
mediante la misma notacin ClassName.MemberName que se usa para los campos estticos. No se requiere ninguna
instancia de objeto.
C# no admite variables locales estticas (variables que se declaran en el mbito del mtodo).
Para declarar miembros de clases estticas, use la palabra clave static antes del tipo de valor devuelto del
miembro, como se muestra en el ejemplo siguiente:
public class Automobile
{
public static int NumberOfWheels = 4;
public static int SizeOfGasTank
{
get
{
return 15;
}
}
public static void Drive() { }
public static event EventType RunOutOfGas;

// Other non-static fields and properties...


}

Los miembros estticos se inicializan antes de que se obtenga acceso por primera vez al miembro esttico y antes
de que se llame al constructor esttico, en caso de haberlo. Para tener acceso a un miembro de clase esttica, use
el nombre de la clase en lugar de un nombre de variable para especificar la ubicacin del miembro, como se
muestra en el ejemplo siguiente:

Automobile.Drive();
int i = Automobile.NumberOfWheels;

Si la clase contiene campos estticos, proporcione un constructor esttico que los inicialice al cargar la clase.
Una llamada a un mtodo esttico genera una instruccin de llamada en Lenguaje Intermedio de Microsoft
(MSIL), mientras que una llamada a un mtodo de instancia genera una instruccin callvirt , que tambin
comprueba si hay referencias a un objeto NULL, pero la mayora de las veces la diferencia de rendimiento entre
las dos no es significativo.

Especificacin del lenguaje C#


Para obtener ms informacin, consulte la Especificacin del lenguaje C#. La especificacin del lenguaje es la
fuente definitiva de la sintaxis y el uso de C#.

Vea tambin
Gua de programacin de C#
static
Clases
class
Constructores estticos
Constructores de instancias
Miembros (Gua de programacin de C#)
03/10/2017 2 min to read Edit Online

Las clases y structs tienen miembros que representan sus datos y comportamiento. Los miembros de una clase
incluyen todos los miembros declarados en la clase, junto con todos los miembros (excepto constructores y
finalizadores) declarados en todas las clases de su jerarqua de herencia. Los miembros privados de clases base se
heredan en las clases derivadas, pero estas no pueden tener acceso a ellos.
En la tabla siguiente se enumeran los tipos de miembros que puede contener una clase o struct:

MIEMBRO DESCRIPCIN

Campos Los campos son variables declaradas en el mbito de clase. Un


campo puede ser un tipo numrico integrado o una instancia
de otra clase. Por ejemplo, una clase de calendario puede
tener un campo con la fecha actual.

Constantes Las constantes son campos o propiedades cuyo valor se


establece en tiempo de compilacin y no se puede cambiar.

Propiedades Las propiedades son mtodos de una clase a los que se


obtiene acceso como si fueran campos de esa clase. Una
propiedad puede proporcionar proteccin a un campo de
clase con el fin de evitar que se cambie sin el conocimiento del
objeto.

Mtodos Los mtodos definen las acciones que una clase puede realizar.
Los mtodos pueden aceptar parmetros que proporcionan
datos de entrada y devolver datos de salida a travs de
parmetros. Los mtodos tambin pueden devolver un valor
directamente, sin usar ningn parmetro.

Eventos Los eventos proporcionan a otros objetos notificaciones sobre


lo que ocurre, como clics en botones o la realizacin correcta
de un mtodo. Los eventos se definen y desencadenan
mediante delegados.

Operadores Los operadores sobrecargados se consideran miembros de


clase. Si se sobrecarga un operador, se define como mtodo
esttico pblico en una clase. Los operadores predefinidos ( +
, * , < , etc.) no se consideran miembros. Para obtener ms
informacin, vea Operadores sobrecargables.

Indizadores Los indizadores permiten indizar un objeto de manera similar


a como se hace con las matrices.

Constructores Los constructores son mtodos a los que se llama cuando el


objeto se crea por primera vez. Se usan a menudo para
inicializar los datos de un objeto.
MIEMBRO DESCRIPCIN

Finalizadores En C#, los finalizadores se usan en raras ocasiones. Son


mtodos a los que llama el motor de ejecucin del runtime
cuando el objeto est a punto de quitarse de la memoria.
Generalmente se utilizan para asegurarse de que los recursos
que se deben liberar se controlan apropiadamente.

Tipos anidados Los tipos anidados son tipos declarados dentro de otro tipo.
Los tipos anidados se usan a menudo para describir objetos
utilizados nicamente por los tipos que los contienen.

Vea tambin
Gua de programacin de C#
Clases
Mtodos
Constructors (Constructores [Gua de programacin de C#])
Finalizadores
Propiedades
Campos
Indexers (Indexadores)
Eventos
Tipos anidados
Operadores
Operadores sobrecargables
Modificadores de acceso (Gua de programacin de
C#)
03/10/2017 4 min to read Edit Online

Todos los tipos y miembros de tipo tienen un nivel de accesibilidad que controla si se pueden usar desde otro
cdigo del ensamblado u otros ensamblados. Puede usar los siguientes modificadores de acceso para especificar
la accesibilidad de un tipo o miembro cuando lo declare:
public
Puede obtener acceso al tipo o miembro cualquier otro cdigo del mismo ensamblado o de otro ensamblado que
haga referencia a ste.
private
Solamente el cdigo de la misma clase o estructura puede acceder al tipo o miembro.
protected
Solamente el cdigo de la misma clase o estructura, o de una clase derivada de esa clase, puede acceder al tipo o
miembro.
internal
Puede obtener acceso al tipo o miembro cualquier cdigo del mismo ensamblado, pero no de un ensamblado
distinto.
protected internal
Cualquier cdigo del ensamblado en el que se ha declarado, o desde cualquier clase derivada de otro ensamblado,
puede acceder al tipo o miembro. El acceso desde otro ensamblado debe producirse en una declaracin de clase
que derive de la clase en la que se haya declarado el elemento interno protegido y se debe realizar mediante una
instancia del tipo de clase derivada.
En los ejemplos siguientes se muestra cmo especificar modificadores de acceso en un tipo y miembro:

public class Bicycle


{
public void Pedal() { }
}

No todos los tipos o miembros pueden usar todos los modificadores de acceso en todos los contextos; en algunos
casos la accesibilidad de un miembro de tipo est restringida por la accesibilidad de su tipo contenedor. En las
secciones siguientes se proporcionan ms detalles sobre la accesibilidad.

Accesibilidad de clase y estructura


Las clases y estructuras que se declaran directamente en un espacio de nombres (es decir, que no estn anidadas
en otras clases o estructuras) pueden ser pblicas o internas. Si no se especifica ningn modificador de acceso, el
valor predeterminado es internal.
Los miembros de estructura, incluidas las clases y las estructuras anidadas, se pueden declarar como public,
internal, o private. Los miembros de clase, incluidas las clases y las estructuras anidadas, pueden ser public,
protected internal, protected, internal o private. El nivel de acceso de los miembros de clase y los miembros de
estructura, incluidas las clases y estructuras anidadas, es private de forma predeterminada. Los tipos anidados
privados no son accesibles desde fuera del tipo contenedor.
Las clases derivadas no pueden tener mayor accesibilidad que sus tipos base. En otras palabras, no puede tener
una clase pblica B que derive de una clase interna A . Si se permitiera, convertira A en pblico, porque todos
los miembros protegidos o internos de A son accesibles desde la clase derivada.
Puede habilitar otros ensamblados concretos para acceder a los tipos internos mediante
InternalsVisibleToAttribute. Para ms informacin, vea Ensamblados de confianza.

Accesibilidad de miembros de clase y estructura


Los miembros de clase (incluidas las clases y las estructuras anidadas) se pueden declarar con cualquiera de los
cinco tipos de acceso. Los miembros de estructura no se pueden declarar como protegidos porque las estructuras
no admiten la herencia.
Normalmente, la accesibilidad de un miembro no es mayor que la del tipo que lo contiene. Pero un miembro
pblico de una clase interna podra ser accesible desde fuera del ensamblado si el miembro implementa los
mtodos de interfaz o invalida los mtodos virtuales definidos en una clase base pblica.
El tipo de cualquier miembro que sea un campo, propiedad o evento debe ser al menos tan accesible como el
propio miembro. Del mismo modo, el tipo devuelto y los tipos de parmetro de cualquier miembro que sea un
mtodo, indizador o delegado deben ser al menos tan accesibles como el propio miembro. Por ejemplo, no puede
tener un mtodo pblico M que devuelva una clase C a menos que C tambin sea pblico. Del mismo modo,
no puede tener una propiedad protegida de tipo A si A se declara como private.
Los operadores definidos por el usuario siempre deben declararse como public. Para ms informacin, vea
Operador (Referencia de C#).
Los finalizadores no pueden tener modificadores de accesibilidad.
Para establecer el nivel de acceso de un miembro de clase o estructura, agregue la palabra clave adecuada a la
declaracin de miembro, como se muestra en el ejemplo siguiente.

// public class:
public class Tricycle
{
// protected method:
protected void Pedal() { }

// private field:
private int wheels = 3;

// protected internal property:


protected internal int Wheels
{
get { return wheels; }
}
}

NOTA
El nivel de accesibilidad protected internal significa protected O internal, no protected E internal. Es decir, se puede acceder a
un miembro protegido interno desde cualquier clase del mismo ensamblado, incluidas las clases derivadas. Para limitar la
accesibilidad a las clases derivadas del mismo ensamblado, declare la propia clase como internal y sus miembros como
protected.

Otros tipos
Las interfaces declaradas directamente en un espacio de nombres se pueden declarar como public o internal y, al
igual que las clases y las estructuras, su valor predeterminado es el acceso interno. Los miembros de interfaz son
siempre pblicos porque el propsito de una interfaz es permitir que otros tipos accedan a una clase o estructura.
A los miembros de interfaz no se les puede aplicar ningn modificador de acceso.
Los miembros de enumeracin siempre son pblicos y no se les puede aplicar ningn modificador de acceso.
Los delegados se comportan como las clases y las estructuras. De forma predeterminada, tienen acceso interno
cuando se declaran directamente en un espacio de nombres y acceso privado cuando estn anidados.

Especificacin del lenguaje C#


Para obtener ms informacin, consulte la Especificacin del lenguaje C#. La especificacin del lenguaje es la
fuente definitiva de la sintaxis y el uso de C#.

Vea tambin
Gua de programacin de C#
Clases y structs
Interfaces
private
public
internal
protected
class
struct
interface
Campos (Gua de programacin de C#)
03/10/2017 4 min to read Edit Online

Un campo es una variable de cualquier tipo que se declara directamente en una clase o struct. Los campos son
miembros de su tipo contenedor.
Una clase o struct puede tener campos de instancia o campos estticos, o ambos. Los campos de instancia son
especficos de una instancia de un tipo. Si tiene una clase T, con un campo de instancia F, puede crear dos objetos
de tipo T y modificar el valor de F en cada objeto sin afectar el valor del otro objeto. Por el contrario, un campo
esttico pertenece a la propia clase y se comparte entre todas las instancias de esa clase. Los cambios realizados
desde la instancia A sern visibles inmediatamente para las instancias B y C, si tienen acceso al campo.
Por lo general, solo se deben usar campos para las variables que tienen accesibilidad privada o protegida. Los
datos que la clase expone al cdigo de cliente deben proporcionarse a travs de mtodos, propiedades e
indizadores. Mediante estas construcciones para el acceso indirecto a los campos internos, se puede proteger de
los valores de entrada no vlidos. Un campo privado que almacena los datos expuestos por una propiedad pblica
se denomina memoria auxiliar o campo de respaldo.
Los campos almacenan habitualmente los datos que deben ser accesibles para ms de un mtodo de clase y que
deben almacenarse durante ms tiempo de lo que dura un nico mtodo. Por ejemplo, es posible que una clase
que representa una fecha de calendario tenga tres campos enteros: uno para el mes, otro para el da y otro para el
ao. Las variables que no se usan fuera del mbito de un nico mtodo se deben declarar como variables locales
dentro del mtodo del propio cuerpo.
Los campos se declaran en el bloque de clase especificando el nivel de acceso del campo, seguido por el tipo del
campo, seguido por el nombre del campo. Por ejemplo:
public class CalendarEntry
{
// private field
private DateTime date;

// public field (Generally not recommended.)


public string day;

// Public property exposes date field safely.


public DateTime Date
{
get
{
return date;
}
set
{
// Set some reasonable boundaries for likely birth dates.
if (value.Year > 1900 && value.Year <= DateTime.Today.Year)
{
date = value;
}
else
throw new ArgumentOutOfRangeException();
}

// Public method also exposes date field safely.


// Example call: birthday.SetDate("1975, 6, 30");
public void SetDate(string dateString)
{
DateTime dt = Convert.ToDateTime(dateString);

// Set some reasonable boundaries for likely birth dates.


if (dt.Year > 1900 && dt.Year <= DateTime.Today.Year)
{
date = dt;
}
else
throw new ArgumentOutOfRangeException();
}

public TimeSpan GetTimeSpan(string dateString)


{
DateTime dt = Convert.ToDateTime(dateString);

if (dt != null && dt.Ticks < date.Ticks)


{
return date - dt;
}
else
throw new ArgumentOutOfRangeException();

}
}

Para obtener acceso a un campo en un objeto, agregue un punto despus del nombre de objeto, seguido del
nombre del campo, como en objectname.fieldname . Por ejemplo:

CalendarEntry birthday = new CalendarEntry();


birthday.day = "Saturday";

Se puede proporcionar un valor inicial a un campo mediante el operador de asignacin cuando se declara el
campo. Para asignar automticamente el campo day a "Monday" , por ejemplo, se declarara day como en el
ejemplo siguiente:

public class CalendarDateWithInitialization


{
public string day = "Monday";
//...
}

Los campos se inicializan inmediatamente antes de que se llame al constructor para la instancia del objeto. Si el
constructor asigna el valor de un campo, sobrescribir cualquier valor dado durante la declaracin del campo. Para
obtener ms informacin, vea Using Constructors (Uso de constructores).

NOTA
Un inicializador de campo no puede hacer referencia a otros campos de instancia.

Los campos se pueden marcar como public, private, protected, internal o protected internal . Estos modificadores
de acceso definen cmo los usuarios de la clase pueden obtener acceso a los campos. Para obtener ms
informacin, vea Modificadores de acceso.
Opcionalmente, un campo se puede declarar como static. Esto hace que el campo est disponible para los
llamadores en cualquier momento, aunque no exista ninguna instancia de la clase. Para obtener ms informacin,
vea Clases estticas y sus miembros.
Se puede declarar un campo como readonly. Solamente se puede asignar un valor a un campo de solo lectura
durante la inicializacin o en un constructor. Un campo static``readonly es muy similar a una constante, salvo
que el compilador de C# no tiene acceso al valor de un campo esttico de solo lectura en tiempo de compilacin,
solo en tiempo de ejecucin. Para obtener ms informacin, vea Constants (Constantes).

Especificacin del lenguaje C#


Para obtener ms informacin, consulte la Especificacin del lenguaje C#. La especificacin del lenguaje es la
fuente definitiva de la sintaxis y el uso de C#.

Vea tambin
Gua de programacin de C#
Clases y structs
Uso de constructores
Herencia
Modificadores de acceso
Clases y miembros de clase abstractos y sellados
Constantes (Gua de programacin de C#)
03/10/2017 2 min to read Edit Online

Las constantes son valores inmutables que se conocen en tiempo de compilacin y que no cambian durante la vida
del programa. Las constantes se declaran con el modificador const. Solo los tipos integrados de C# (excluido
System.Object) pueden declararse como const . Para obtener una lista de los tipos integrados, vea Tabla de tipos
integrados. Los tipos definidos por el usuario, incluidas las clases, las estructuras y las matrices, no pueden ser
const . Use el modificador readonly para crear una clase, una estructura o una matriz que se inicialice una vez en
tiempo de ejecucin (por ejemplo, en un constructor) y que posteriormente no se pueda cambiar.
C# no admite mtodos, propiedades ni eventos const .
El tipo enum permite definir constantes con nombre para los tipos integrados enteros (por ejemplo, int , uint ,
long , etc.). Para ms informacin, vea enum.

Las constantes se deben inicializar al declararse. Por ejemplo:

class Calendar1
{
public const int months = 12;
}

En este ejemplo la constante months siempre es 12 y ni siquiera la propia clase la puede cambiar. De hecho,
cuando el compilador detecta un identificador de constante en el cdigo fuente de C# (por ejemplo, months ),
sustituye directamente el valor literal en el cdigo de lenguaje intermedio (IL) que genera. Dado que no hay
ninguna direccin de variable asociada a una constante en tiempo de ejecucin, no se pueden pasar los campos
const por referencia ni pueden aparecer como un valor L en una expresin.

NOTA
Tenga cuidado al hacer referencia a valores de constante definidos en otro cdigo como archivos DLL. Si una nueva versin
del archivo DLL define un nuevo valor para la constante, el programa conservar el valor literal anterior hasta que se vuelva a
compilar con la versin nueva.

Se pueden declarar varias constantes del mismo tipo a la vez, por ejemplo:

class Calendar2
{
const int months = 12, weeks = 52, days = 365;
}

La expresin que se usa para inicializar una constante puede hacer referencia a otra constante si no crea una
referencia circular. Por ejemplo:
class Calendar3
{
const int months = 12;
const int weeks = 52;
const int days = 365;

const double daysPerWeek = (double) days / (double) weeks;


const double daysPerMonth = (double) days / (double) months;
}

Las constantes se pueden marcar como public, private, protected, internal o protected internal . Estos
modificadores de acceso definen cmo los usuarios de la clase pueden acceder a la constante. Para ms
informacin, vea Modificadores de acceso.
A las constantes se accede como si fueran campos estticos porque el valor de la constante es el mismo para todas
las instancias del tipo. No use la palabra clave static para declararlas. Las expresiones que no estn en la clase
que define la constante deben usar el nombre de la clase, un punto y el nombre de la constante para acceder a ella.
Por ejemplo:

int birthstones = Calendar.months;

Especificacin del lenguaje C#


Para obtener ms informacin, consulte la Especificacin del lenguaje C#. La especificacin del lenguaje es la
fuente definitiva de la sintaxis y el uso de C#.

Vea tambin
Gua de programacin de C#
Clases y structs
Propiedades
Tipos
readonly
Immutability in C# Part One: Kinds of Immutability (Inmutabilidad en C# (primera parte): tipos de inmutabilidad)
Cmo: Definir constantes en C#
03/10/2017 1 min to read Edit Online

Las constantes son campos cuyos valores se establecen en tiempo de compilacin y nunca se pueden cambiar. Use
constantes para proporcionar nombres descriptivos en lugar de literales numricos ("nmeros mgicos") para
valores especiales.

NOTA
En C#, la directiva del preprocesador #define no puede usarse para definir constantes en la manera que se usa normalmente
en C y C++.

Para definir valores constantes de tipos enteros ( int , byte y as sucesivamente) use un tipo enumerado. Para
ms informacin, vea enum.
Para definir constantes no enteras, un enfoque es agruparlas en una nica clase esttica denominada Constants .
Esto necesitar que todas las referencias a las constantes vayan precedidas por el nombre de clase, como se
muestra en el ejemplo siguiente.

Ejemplo
static class Constants
{
public const double Pi = 3.14159;
public const int SpeedOfLight = 300000; // km per sec.

}
class Program
{
static void Main()
{
double radius = 5.3;
double area = Constants.Pi * (radius * radius);
int secsFromSun = 149476000 / Constants.SpeedOfLight; // in km
}
}

El uso del calificador de nombre de clase ayuda a garantizar que usted y otros usuarios que usan la constante
comprenden que es una constante y que no puede modificarse.

Vea tambin
Clases y structs
Propiedades (Gua de programacin de C#)
03/10/2017 5 min to read Edit Online

Una propiedad es un miembro que proporciona un mecanismo flexible para leer, escribir o calcular el valor de
un campo privado. Las propiedades se pueden usar como si fueran miembros de datos pblicos, pero en
realidad son mtodos especiales denominados descriptores de acceso. Esto permite acceder fcilmente a los
datos a la vez que proporciona la seguridad y la flexibilidad de los mtodos.

Informacin general sobre propiedades


Las propiedades permiten que una clase exponga una manera pblica de obtener y establecer valores, a la
vez que se oculta el cdigo de implementacin o comprobacin.
Para devolver el valor de la propiedad se usa un descriptor de acceso de propiedad get, mientras que para
asignar un nuevo valor se emplea un descriptor de acceso de propiedad set. Estos descriptores de acceso
pueden tener diferentes niveles de acceso. Para ms informacin, vea Restringir la accesibilidad del
descriptor de acceso.
La palabra clave value se usa para definir el valor que va a asignar el descriptor de acceso set .
Las propiedades pueden ser de lectura y escritura (en ambos casos tienen un descriptor de acceso get y
set ), de solo lectura (tienen un descriptor de acceso get , pero no set ) o de solo escritura (tienen un
descriptor de acceso set , pero no get ). Las propiedades de solo escritura son poco frecuentes y se
suelen usar para restringir el acceso a datos confidenciales.
Las propiedades simples que no necesitan ningn cdigo de descriptor de acceso personalizado se
pueden implementar como definiciones de cuerpos de expresin o como propiedades implementadas
automticamente.

Propiedades con campos de respaldo


Un patrn bsico para implementar una propiedad conlleva el uso de un campo de respaldo privado para
establecer y recuperar el valor de la propiedad. El descriptor de acceso get devuelve el valor del campo privado
y el descriptor de acceso set puede realizar alguna validacin de datos antes de asignar un valor al campo
privado. Ambos descriptores de acceso adems pueden realizar algn clculo o conversin en los datos antes de
que se almacenen o se devuelvan.
En el ejemplo siguiente se muestra este patrn. En este ejemplo, la clase TimePeriod representa un intervalo de
tiempo. Internamente, la clase almacena el intervalo de tiempo en segundos en un campo privado denominado
seconds . Una propiedad de lectura y escritura denominada Hours permite al cliente especificar el intervalo de
tiempo en horas. Los descriptores de acceso get y set realizan la conversin necesaria entre horas y
segundos. Adems, el descriptor de acceso set valida los datos e inicia una excepcin
ArgumentOutOfRangeException si el nmero de horas no es vlido.
using System;

class TimePeriod
{
private double seconds;

public double Hours


{
get { return seconds / 3600; }
set {
if (value < 0 || value > 24)
throw new ArgumentOutOfRangeException(
$"{nameof(value)} must be between 0 and 24.");

seconds = value * 3600;


}
}
}

class Program
{
static void Main()
{
TimePeriod t = new TimePeriod();
// The property assignment causes the 'set' accessor to be called.
t.Hours = 24;

// Retrieving the property causes the 'get' accessor to be called.


Console.WriteLine($"Time in hours: {t.Hours}");
}
}
// The example displays the following output:
// Time in hours: 24

Definiciones de cuerpos de expresin


Los descriptores de acceso de propiedad suelen constar de instrucciones de una sola lnea que simplemente
asignan o devuelven el resultado de una expresin. Puede implementar estas propiedades como miembros con
forma de expresin. Las definiciones de cuerpos de expresin constan del smbolo => seguido de la expresin
que se va a asignar a la propiedad o a recuperar de ella.
A partir de C# 6, las propiedades de solo lectura pueden implementar el descriptor de acceso get como
miembro con forma de expresin. En este caso, no se usan ni la palabra clave del descriptor de acceso get ni la
palabra clave return . En el ejemplo siguiente se implementa la propiedad de solo lectura Name como miembro
con forma de expresin.
using System;

public class Person


{
private string firstName;
private string lastName;

public Person(string first, string last)


{
firstName = first;
lastName = last;
}

public string Name => $"{firstName} {lastName}";


}

public class Example


{
public static void Main()
{
var person = new Person("Isabelle", "Butts");
Console.WriteLine(person.Name);
}
}
// The example displays the following output:
// Isabelle Butts

A partir de C# 7, los descriptores de acceso get y set se pueden implementar como miembros con forma de
expresin. En este caso, las palabras clave get y set deben estar presentes. En el ejemplo siguiente se muestra
el uso de definiciones de cuerpos de expresin para ambos descriptores de acceso. Observe que no se usa la
palabra clave return con el descriptor de acceso get .
using System;

public class SaleItem


{
string name;
decimal cost;

public SaleItem(string name, decimal cost)


{
this.name = name;
this.cost = cost;
}

public string Name


{
get => name;
set => name = value;
}

public decimal Price


{
get => cost;
set => cost = value;
}
}

class Program
{
static void Main(string[] args)
{
var item = new SaleItem("Shoes", 19.95m);
Console.WriteLine($"{item.Name}: sells for {item.Price:C2}");
}
}
// The example displays output like the following:
// Shoes: sells for $19.95

Propiedades implementadas automticamente


En algunos casos, los descriptores de acceso de propiedad get y set simplemente asignan un valor a un
campo de respaldo o recuperan un valor de l sin incluir ninguna lgica adicional. Mediante las propiedades
implementadas automticamente, puede simplificar el cdigo y conseguir que el compilador de C# le
proporcione el campo de respaldo de forma transparente.
Si una propiedad tiene un descriptor de acceso get y set , ambos deben ser implementados automticamente.
Una propiedad implementada automticamente se define mediante las palabras clave get y set sin
proporcionar ninguna implementacin. El ejemplo siguiente repite el anterior, salvo que Name y Price son
propiedades implementadas automticamente. Observe que en el ejemplo tambin se quita el constructor
parametrizado, por lo que los objetos SaleItem ahora se inicializan con una llamada al constructor
predeterminado y un inicializador de objeto.
using System;

public class SaleItem


{
public string Name
{ get; set; }

public decimal Price


{ get; set; }
}

class Program
{
static void Main(string[] args)
{
var item = new SaleItem{ Name = "Shoes", Price = 19.95m };
Console.WriteLine($"{item.Name}: sells for {item.Price:C2}");
}
}
// The example displays output like the following:
// Shoes: sells for $19.95

Secciones relacionadas
Utilizar propiedades
Propiedades de interfaz
Comparacin entre propiedades e indizadores
Restringir la accesibilidad del descriptor de acceso
Propiedades autoimplementadas

Especificacin del lenguaje C#


Para obtener ms informacin, consulte la Especificacin del lenguaje C#. La especificacin del lenguaje es la
fuente definitiva de la sintaxis y el uso de C#.

Vea tambin
Gua de programacin de C#
Utilizar propiedades
Indizadores
get (palabra clave)
set (palabra clave)
Utilizar propiedades (Gua de programacin de C#)
03/10/2017 9 min to read Edit Online

Las propiedades combinan aspectos de los campos y los mtodos. Para el usuario de un objeto, una propiedad
que parece un campo, el acceso a la propiedad necesita la misma sintaxis. Para el implementador de una clase, una
propiedad es uno o dos bloques de cdigo que representa un descriptor de acceso get o un descriptor de acceso
set. El bloque de cdigo del descriptor de acceso get se ejecuta cuando se lee la propiedad; el bloque de cdigo
del descriptor de acceso set se ejecuta cuando se asigna un nuevo valor a la propiedad. Una propiedad sin un
descriptor de acceso set se considera de solo lectura. Una propiedad sin un descriptor de acceso get se
considera de solo escritura. Una propiedad que tiene ambos descriptores de acceso es de lectura y escritura.
A diferencia de los campos, las propiedades no se clasifican como variables. Por lo tanto, no puede pasar una
propiedad como un parmetro ref u out.
Las propiedades tienen muchos usos: pueden validar datos antes de permitir un cambio; pueden exponer
claramente datos en una clase donde esos datos se recuperan realmente de otros orgenes, como una base de
datos; pueden realizar una accin cuando los datos se cambian, como generar un evento, o cambiar el valor de
otros campos.
Las propiedades se declaran en el bloque de clase especificando el nivel de acceso del campo, seguido del tipo de
la propiedad, seguido del nombre de la propiedad y seguido de un bloque de cdigo que declara un descriptor de
acceso get o un descriptor de acceso set . Por ejemplo:

public class Date


{
private int month = 7; // Backing store

public int Month


{
get
{
return month;
}
set
{
if ((value > 0) && (value < 13))
{
month = value;
}
}
}
}

En este ejemplo, Month se declara como una propiedad, de manera que el descriptor de acceso set pueda estar
seguro de que el valor Month se establece entre 1 y 12. La propiedad Month usa un campo privado para realizar
un seguimiento del valor actual. A menudo, a la ubicacin real de los datos de una propiedad se le conoce como la
"memoria auxiliar" de la propiedad. Esto es comn para las propiedades que usan campos privados como una
memoria auxiliar. El campo se marca como privado para asegurarse de que solo puede cambiarse llamando a la
propiedad. Para obtener ms informacin sobre las restricciones de acceso pblico y privado, vea Modificadores
de acceso.
Las propiedades implementadas automticamente proporcionan una sintaxis simplificada para las declaraciones
de propiedad simples. Para obtener ms informacin, vea Propiedades implementadas automticamente.
El descriptor de acceso get
El cuerpo del descriptor de acceso get se parece al de un mtodo. Debe devolver un valor del tipo de propiedad.
La ejecucin del descriptor de acceso get es equivalente a la lectura del valor del campo. Por ejemplo, cuando se
devuelve la variable privada del descriptor de acceso get y se habilitan las optimizaciones, la llamada al mtodo
de descriptor de acceso get se inserta mediante el compilador, de manera que no existe ninguna sobrecarga de
llamada al mtodo. En cambio, un mtodo de descriptor de acceso get virtual no puede insertarse porque el
compilador no conoce en tiempo de compilacin a qu mtodo puede llamarse realmente en tiempo de ejecucin.
A continuacin se muestra un descriptor de acceso get que devuelve el valor de un campo privado name :

class Person
{
private string name; // the name field
public string Name // the Name property
{
get
{
return name;
}
}
}

Cuando hace referencia a la propiedad, excepto como el destino de una asignacin, el descriptor de acceso get se
invoca para leer el valor de la propiedad. Por ejemplo:

Person person = new Person();


//...

System.Console.Write(person.Name); // the get accessor is invoked here

El descriptor de acceso get debe finalizar en una instruccin return o throw, y el control no puede salir del cuerpo
del descriptor de acceso.
Cambiar el estado del objeto mediante el descriptor de acceso get es un estilo de programacin incorrecto. Por
ejemplo, el siguiente descriptor de acceso produce el efecto secundario de cambiar el estado del objeto cada vez
que se tiene acceso al campo number .

private int number;


public int Number
{
get
{
return number++; // Don't do this
}
}

El descriptor de acceso get puede usarse para devolver el valor de campo o para calcularlo y devolverlo. Por
ejemplo:
class Employee
{
private string name;
public string Name
{
get
{
return name != null ? name : "NA";
}
}
}

En el segmento de cdigo anterior, si no asigna un valor a la propiedad Name , devolver el valor NA.

El descriptor de acceso set


El descriptor de acceso set es similar a un mtodo cuyo tipo de valor devuelto es void. Usa un parmetro
implcito denominado value , cuyo tipo es el tipo de la propiedad. En el siguiente ejemplo, se agrega un descriptor
de acceso set a la propiedad Name :

class Person
{
private string name; // the name field
public string Name // the Name property
{
get
{
return name;
}
set
{
name = value;
}
}
}

Cuando asigna un valor a la propiedad, el descriptor de acceso set se invoca mediante un argumento que
proporciona el valor nuevo. Por ejemplo:

Person person = new Person();


person.Name = "Joe"; // the set accessor is invoked here

System.Console.Write(person.Name); // the get accessor is invoked here

Es un error usar el nombre de parmetro implcito, value , para una declaracin de variable local en el descriptor
de acceso set .

Comentarios
Las propiedades pueden marcarse como public , private , protected , internal o protected internal . Estos
modificadores de acceso definen cmo los usuarios de la clase pueden obtener acceso a la propiedad. Los
descriptores de acceso get y set para la misma propiedad pueden tener diferentes modificadores de acceso.
Por ejemplo, get puede ser public para permitir el acceso de solo lectura desde el exterior del tipo, y set
puede ser private o protected . Para ms informacin, vea Modificadores de acceso.
Una propiedad puede declararse como una propiedad esttica mediante la palabra clave static . Esto hace que la
propiedad est disponible para los autores de la llamada en cualquier momento, aunque no exista ninguna
instancia de la clase. Para ms informacin, vea Clases estticas y sus miembros.
Una propiedad puede marcarse como una propiedad virtual mediante la palabra clave virtual. Esto permite que las
clases derivadas invaliden el comportamiento de la propiedad mediante la palabra clave override. Para obtener
ms informacin sobre estas opciones, vea Herencia.
Una propiedad que invalida una propiedad virtual tambin puede sellarse, que especifica que para las clases
derivadas ya no es virtual. Por ltimo, una propiedad puede declararse abstracta. Esto significa que no existe
ninguna implementacin en la clase, y las clases derivadas deben escribir su propia implementacin. Para obtener
ms informacin sobre estas opciones, vea Abstract and Sealed Classes and Class Members (Clases y miembros
de clase abstractos y sellados [Gua de programacin de C#]).

NOTA
Es un error usar un modificador virtual, abstract u override en un descriptor de acceso de una propiedad static.

Ejemplo
En este ejemplo se muestran las propiedades de solo lectura, estticas y de instancia. Acepta el nombre del
empleado desde el teclado, incrementa NumberOfEmployees en 1 y muestra el nombre del empleado y el nmero.
public class Employee
{
public static int NumberOfEmployees;
private static int counter;
private string name;

// A read-write instance property:


public string Name
{
get { return name; }
set { name = value; }
}

// A read-only static property:


public static int Counter
{
get { return counter; }
}

// A Constructor:
public Employee()
{
// Calculate the employee's number:
counter = ++counter + NumberOfEmployees;
}
}

class TestEmployee
{
static void Main()
{
Employee.NumberOfEmployees = 107;
Employee e1 = new Employee();
e1.Name = "Claude Vige";

System.Console.WriteLine("Employee number: {0}", Employee.Counter);


System.Console.WriteLine("Employee name: {0}", e1.Name);
}
}
/* Output:
Employee number: 108
Employee name: Claude Vige
*/

Ejemplo
En este ejemplo se muestra cmo tener acceso a una propiedad en una clase base que est oculta mediante otra
propiedad que tiene el mismo nombre en una clase derivada.
public class Employee
{
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
}

public class Manager : Employee


{
private string name;

// Notice the use of the new modifier:


public new string Name
{
get { return name; }
set { name = value + ", Manager"; }
}
}

class TestHiding
{
static void Main()
{
Manager m1 = new Manager();

// Derived class property.


m1.Name = "John";

// Base class property.


((Employee)m1).Name = "Mary";

System.Console.WriteLine("Name in the derived class is: {0}", m1.Name);


System.Console.WriteLine("Name in the base class is: {0}", ((Employee)m1).Name);
}
}
/* Output:
Name in the derived class is: John, Manager
Name in the base class is: Mary
*/

A continuacin se muestran puntos importantes del ejemplo anterior:


La propiedad Name de la clase derivada oculta la propiedad Name de la clase base. En dicho caso, el
modificador new se usa en la declaracin de la propiedad en la clase derivada:

public new string Name

La conversin (Employee) se usa para tener acceso a la propiedad oculta de la clase base:

((Employee)m1).Name = "Mary";

Para obtener ms informacin sobre cmo ocultar miembros, vea el Modificador new.

Ejemplo
En este ejemplo, dos clases, Cube y Square , implementan una clase abstracta, Shape , e invalidan su propiedad
Area abstracta. Tenga en cuenta el uso del modificador override en las propiedades. El programa acepta el lado
como una entrada y calcula las reas del cuadrado y el cubo. Tambin acepta el rea como una entrada y calcula el
lado correspondiente para el cuadrado y el cubo.

abstract class Shape


{
public abstract double Area
{
get;
set;
}
}

class Square : Shape


{
public double side;

public Square(double s) //constructor


{
side = s;
}

public override double Area


{
get
{
return side * side;
}
set
{
side = System.Math.Sqrt(value);
}
}
}

class Cube : Shape


{
public double side;

public Cube(double s)
{
side = s;
}

public override double Area


{
get
{
return 6 * side * side;
}
set
{
side = System.Math.Sqrt(value / 6);
}
}
}

class TestShapes
{
static void Main()
{
// Input the side:
System.Console.Write("Enter the side: ");
double side = double.Parse(System.Console.ReadLine());

// Compute the areas:


Square s = new Square(side);
Cube c = new Cube(side);

// Display the results:


// Display the results:
System.Console.WriteLine("Area of the square = {0:F2}", s.Area);
System.Console.WriteLine("Area of the cube = {0:F2}", c.Area);
System.Console.WriteLine();

// Input the area:


System.Console.Write("Enter the area: ");
double area = double.Parse(System.Console.ReadLine());

// Compute the sides:


s.Area = area;
c.Area = area;

// Display the results:


System.Console.WriteLine("Side of the square = {0:F2}", s.side);
System.Console.WriteLine("Side of the cube = {0:F2}", c.side);
}
}
/* Example Output:
Enter the side: 4
Area of the square = 16.00
Area of the cube = 96.00

Enter the area: 24


Side of the square = 4.90
Side of the cube = 2.00
*/

Vea tambin
Gua de programacin de C#
Propiedades
Propiedades de interfaz
Propiedades autoimplementadas
Propiedades de interfaces (Gua de programacin de
C#)
03/10/2017 2 min to read Edit Online

Las propiedades se pueden declarar en una interfaz. A continuacin tiene un ejemplo de un descriptor de acceso
de indexador de interfaz:

public interface ISampleInterface


{
// Property declaration:
string Name
{
get;
set;
}
}

El descriptor de acceso de una propiedad de interfaz no tiene un cuerpo. Por tanto, el propsito de los descriptores
de acceso es indicar si la propiedad es de lectura y escritura, de solo lectura o de solo escritura.

Ejemplo
En este ejemplo, la interfaz IEmployee tiene una propiedad de lectura y escritura, Name , y una propiedad de solo
lectura, Counter . La clase Employee implementa la interfaz IEmployee y usa estas dos propiedades. El programa
lee el nombre de un nuevo empleado y el nmero actual de empleados y muestra el nombre del empleado y el
nmero de empleados calculado.
Puede usar el nombre completo de la propiedad, que hace referencia a la interfaz en la que se declara el miembro.
Por ejemplo:

string IEmployee.Name
{
get { return "Employee Name"; }
set { }
}

Se denomina implementacin de interfaz explcita. Por ejemplo, si la clase Employee implementa dos interfaces
ICitizen y IEmployee , y ambas interfaces tienen la propiedad Name , la implementacin del miembro de interfaz
explcita ser necesaria. Es decir, la siguiente declaracin de propiedad:

string IEmployee.Name
{
get { return "Employee Name"; }
set { }
}

implementa la propiedad Name en la interfaz IEmployee , mientras que la siguiente declaracin:


string ICitizen.Name
{
get { return "Citizen Name"; }
set { }
}

implementa la propiedad Name en la interfaz ICitizen .


interface IEmployee
{
string Name
{
get;
set;
}

int Counter
{
get;
}
}

public class Employee : IEmployee


{
public static int numberOfEmployees;

private string name;


public string Name // read-write instance property
{
get
{
return name;
}
set
{
name = value;
}
}

private int counter;


public int Counter // read-only instance property
{
get
{
return counter;
}
}

public Employee() // constructor


{
counter = ++counter + numberOfEmployees;
}
}

class TestEmployee
{
static void Main()
{
System.Console.Write("Enter number of employees: ");
Employee.numberOfEmployees = int.Parse(System.Console.ReadLine());

Employee e1 = new Employee();


System.Console.Write("Enter the name of the new employee: ");
e1.Name = System.Console.ReadLine();

System.Console.WriteLine("The employee information:");


System.Console.WriteLine("Employee number: {0}", e1.Counter);
System.Console.WriteLine("Employee name: {0}", e1.Name);
}
}

210 Hazem Abolrous


Resultados del ejemplo
Enter number of employees: 210

Enter the name of the new employee: Hazem Abolrous

The employee information:

Employee number: 211

Employee name: Hazem Abolrous

Vea tambin
Gua de programacin de C#
Propiedades
Utilizar propiedades
Comparacin entre propiedades e indizadores
Indexers (Indexadores)
Interfaces
Restringir la accesibilidad del descriptor de acceso
(Gua de programacin de C#)
03/10/2017 4 min to read Edit Online

Las partes get y set de una propiedad o un indexador se denominan descriptores de acceso. De forma
predeterminada, estos descriptores de acceso tienen la misma visibilidad o nivel de acceso: los de la propiedad o el
indexador al que pertenecen. Para obtener ms informacin, vea Niveles de accesibilidad. En cambio, a veces
resulta til restringir el acceso a uno de estos descriptores de acceso. Normalmente, esto implica restringir la
accesibilidad del descriptor de acceso set , mientras que se mantiene el descriptor de acceso get accesible
pblicamente. Por ejemplo:

private string name = "Hello";

public string Name


{
get
{
return name;
}
protected set
{
name = value;
}
}

En este ejemplo, una propiedad denominada Name define un descriptor de acceso get y set . El descriptor de
acceso get recibe el nivel de accesibilidad de la propiedad, public en este caso, mientras que el descriptor de
acceso set se restringe explcitamente al aplicar el modificador de acceso protected al propio descriptor de
acceso.

Restricciones en los modificadores de acceso en descriptores de acceso


Usar los modificadores de descriptor de acceso en propiedades o indexadores est sujeto a estas condiciones:
No puede usar los modificadores de descriptor de acceso en una interfaz o en una implementacin explcita
del miembro interface.
Puede usar modificadores de descriptor de acceso solo si la propiedad o el indexador tienen los
descriptores de acceso set y get . En este caso, se permite el modificador solo en uno de los dos
descriptores de acceso.
Si la propiedad o el indexador tienen un modificador override, el modificador de descriptor de acceso debe
coincidir con el descriptor de acceso del descriptor de acceso invalidado, si lo hay.
El nivel de accesibilidad del descriptor de acceso debe ser ms restrictivo que el nivel de accesibilidad de la
propiedad o el indexador.

Modificadores de acceso en descriptores de acceso de invalidacin


Al invalidar una propiedad o un indexador, los descriptores de acceso invalidados deben ser accesibles para el
cdigo de invalidacin. Adems, el nivel de accesibilidad de la propiedad y el indexador (y el de los descriptores de
acceso) debe coincidir con la propiedad y el indexador invalidados correspondientes y los descriptores de acceso.
Por ejemplo:

public class Parent


{
public virtual int TestProperty
{
// Notice the accessor accessibility level.
protected set { }

// No access modifier is used here.


get { return 0; }
}
}
public class Kid : Parent
{
public override int TestProperty
{
// Use the same accessibility level as in the overridden accessor.
protected set { }

// Cannot use access modifier here.


get { return 0; }
}
}

Implementar interfaces
Al usar un descriptor de acceso para implementar una interfaz, este no puede tener un modificador de acceso. En
cambio, si implementa la interfaz con un descriptor de acceso, como get , el otro descriptor de acceso puede tener
un modificador de acceso, como en el ejemplo siguiente:

public interface ISomeInterface


{
int TestProperty
{
// No access modifier allowed here
// because this is an interface.
get;
}
}

public class TestClass : ISomeInterface


{
public int TestProperty
{
// Cannot use access modifier here because
// this is an interface implementation.
get { return 10; }

// Interface property does not have set accessor,


// so access modifier is allowed.
protected set { }
}
}

Dominio de accesibilidad de descriptor de acceso


Si usa un modificador de acceso en el descriptor de acceso, el dominio de accesibilidad del descriptor de acceso
viene determinado por este modificador.
Si no ha usado un modificador de acceso en el descriptor de acceso, el dominio de accesibilidad del descriptor de
acceso viene determinado por el nivel de accesibilidad de la propiedad o el indexador.

Ejemplo
En el ejemplo siguiente, se incluyen tres clases: BaseClass , DerivedClass y MainClass . Hay dos propiedades en
BaseClass , Name y Id en ambas clases. En el ejemplo, se muestra cmo la propiedad Id en DerivedClass se
puede ocultar con la propiedad Id en BaseClass al usar un modificador de acceso restrictivo como protected o
private. Por tanto, cuando asigna valores a esta propiedad, se llama en su lugar a la propiedad en la clase
BaseClass . Si se reemplaza el modificador de acceso por public, la propiedad ser accesible.

En el ejemplo, tambin se muestra que un modificador de acceso restrictivo, como private o protected , en el
descriptor de acceso set de la propiedad Name en DerivedClass impide el acceso al descriptor de acceso y
genera un error al asignrselo.

public class BaseClass


{
private string name = "Name-BaseClass";
private string id = "ID-BaseClass";

public string Name


{
get { return name; }
set { }
}

public string Id
{
get { return id; }
set { }
}
}

public class DerivedClass : BaseClass


{
private string name = "Name-DerivedClass";
private string id = "ID-DerivedClass";

new public string Name


{
get
{
return name;
}

// Using "protected" would make the set accessor not accessible.


set
{
name = value;
}
}

// Using private on the following property hides it in the Main Class.


// Any assignment to the property will use Id in BaseClass.
new private string Id
{
get
{
return id;
}
set
{
id = value;
}
}
}
}

class MainClass
{
static void Main()
{
BaseClass b1 = new BaseClass();
DerivedClass d1 = new DerivedClass();

b1.Name = "Mary";
d1.Name = "John";

b1.Id = "Mary123";
d1.Id = "John123"; // The BaseClass.Id property is called.

System.Console.WriteLine("Base: {0}, {1}", b1.Name, b1.Id);


System.Console.WriteLine("Derived: {0}, {1}", d1.Name, d1.Id);

// Keep the console window open in debug mode.


System.Console.WriteLine("Press any key to exit.");
System.Console.ReadKey();
}
}
/* Output:
Base: Name-BaseClass, ID-BaseClass
Derived: John, ID-BaseClass
*/

Comentarios
Tenga en cuenta que, si reemplaza la declaracin new private string Id por new public string Id , obtendr el
resultado:
Name and ID in the base class: Name-BaseClass, ID-BaseClass

Name and ID in the derived class: John, John123

Vea tambin
Gua de programacin de C#
Propiedades
Indexers (Indexadores)
Modificadores de acceso
Cmo: Declarar y usar propiedades de lectura y
escritura (Gua de programacin de C#)
03/10/2017 2 min to read Edit Online

Las propiedades proporcionan la comodidad de los miembros de datos pblicos sin los riesgos que provienen del
acceso sin comprobar, sin controlar y sin proteger a los datos de un objeto. Esto se consigue mediante los
descriptores de acceso: mtodos especiales que asignan y recuperan valores del miembro de datos subyacente. El
descriptor de acceso set permite que los miembros de datos se asignen, y el descriptor de acceso get recupera los
valores de los miembros de datos.
En este ejemplo se muestra una clase Person que tiene dos propiedades: Name (string) y Age (int). Ambas
propiedades proporcionan descriptores de acceso get y set , de manera que se consideran propiedades de
lectura y escritura.

Ejemplo
class Person
{
private string name = "N/A";
private int age = 0;

// Declare a Name property of type string:


public string Name
{
get
{
return name;
}
set
{
name = value;
}
}

// Declare an Age property of type int:


public int Age
{
get
{
return age;
}

set
{
age = value;
}
}

public override string ToString()


{
return "Name = " + Name + ", Age = " + Age;
}
}

class TestPerson
{
static void Main()
{
{
// Create a new Person object:
Person person = new Person();

// Print out the name and the age associated with the person:
Console.WriteLine("Person details - {0}", person);

// Set some values on the person object:


person.Name = "Joe";
person.Age = 99;
Console.WriteLine("Person details - {0}", person);

// Increment the Age property:


person.Age += 1;
Console.WriteLine("Person details - {0}", person);

// Keep the console window open in debug mode.


Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
/* Output:
Person details - Name = N/A, Age = 0
Person details - Name = Joe, Age = 99
Person details - Name = Joe, Age = 100
*/

Programacin slida
En el ejemplo anterior, las propiedades Name y Age son pblicas e incluyen un descriptor de acceso get y set .
Esto permite que cualquier objeto lea y escriba estas propiedades. En cambio, a veces esto es conveniente para
excluir uno de los descriptores de acceso. Omitir el descriptor de acceso set , por ejemplo, hace que la propiedad
sea de solo lectura:

public string Name


{
get
{
return name;
}
}

De manera alternativa, puede exponer un descriptor de acceso pblicamente pero hacer que el otro sea privado o
est protegido. Para obtener ms informacin, vea Accesibilidad del descriptor de acceso asimtrico.
Una vez que se declaren las propiedades, pueden usarse como si fueran campos de la clase. Esto permite una
sintaxis muy natural cuando ambos obtienen y establecen el valor de una propiedad, como se muestra en las
instrucciones siguientes:

person.Name = "Joe";
person.Age = 99;

Tenga en cuenta que en un mtodo set de la propiedad est disponible una variable value especial. Esta variable
contiene el valor que el usuario ha especificado, por ejemplo:

name = value;

Tenga en cuenta la sintaxis pura para incrementar la propiedad Age en un objeto Person :
person.Age += 1;

Si los mtodos set y get independientes se han usado para modelar las propiedades, el cdigo equivalente
puede tener este aspecto:

person.SetAge(person.GetAge() + 1);

El mtodo ToString se invalida en este ejemplo:

public override string ToString()


{
return "Name = " + Name + ", Age = " + Age;
}

Tenga en cuenta que ToString no se usa explcitamente en el programa. Se invoca de manera predeterminada
mediante las llamadas a WriteLine .

Vea tambin
Gua de programacin de C#
Propiedades
Clases y structs
Propiedades autoimplementadas (Gua de
programacin de C#)
03/10/2017 1 min to read Edit Online

En C# 3.0 y versiones posteriores, las propiedades implementadas automticamente hacen que la declaracin de
propiedades sea ms concisa cuando no es necesaria ninguna lgica adicional en los descriptores de acceso de la
propiedad. Tambin permite que el cdigo de cliente cree objetos. Cuando se declara una propiedad tal como se
muestra en el ejemplo siguiente, el compilador crea un campo de respaldo privado y annimo al que solo se
puede acceder con los descriptores de acceso de propiedad get y set .

Ejemplo
En el ejemplo siguiente se muestra una clase simple que tiene algunas propiedades implementadas
automticamente:

// This class is mutable. Its data can be modified from


// outside the class.
class Customer
{
// Auto-Impl Properties for trivial get and set
public double TotalPurchases { get; set; }
public string Name { get; set; }
public int CustomerID { get; set; }

// Constructor
public Customer(double purchases, string name, int ID)
{
TotalPurchases = purchases;
Name = name;
CustomerID = ID;
}
// Methods
public string GetContactInfo() {return "ContactInfo";}
public string GetTransactionHistory() {return "History";}

// .. Additional methods, events, etc.


}

class Program
{
static void Main()
{
// Intialize a new object.
Customer cust1 = new Customer ( 4987.63, "Northwind",90108 );

//Modify a property
cust1.TotalPurchases += 499.99;
}
}

En C# 6 y versiones posteriores, puede inicializar las propiedades implementadas automticamente de forma


similar a los campos:

public string FirstName { get; set; } = "Jane";


La clase que se muestra en el ejemplo anterior es mutable. El cdigo de cliente puede cambiar los valores de los
objetos una vez creados. En clases complejas que contienen el comportamiento importante (mtodos) y los datos,
suele ser necesario tener propiedades pblicas. Pero para clases pequeas o structs que simplemente encapsulan
un conjunto de valores (datos) y tienen pocos comportamientos o ninguno, debe establecer que los objetos sean
inmutables ya sea declarando el descriptor de acceso set como private (inmutable para los consumidores) o
declarando solo un descriptor de acceso get (inmutable siempre excepto en el constructor). Para obtener ms
informacin, vea Cmo: Implementar una clase ligera con propiedades autoimplementadas.
Los atributos se permiten en propiedades implementadas automticamente, pero obviamente no en los campos
de respaldo, ya que no se puede acceder a ellos desde el cdigo fuente. Si necesita usar un atributo en el campo
de respaldo de una propiedad, cree una propiedad normal.

Vea tambin
Propiedades
Modificadores
Cmo: Implementar una clase ligera con propiedades
autoimplementadas (Gua de programacin de C#)
03/10/2017 2 min to read Edit Online

En este ejemplo se muestra cmo crear una clase ligera inmutable que solo sirve para encapsular un conjunto de
propiedades autoimplementadas. Use este tipo de construccin en lugar de un struct cuando deba utilizar una
semntica de tipo de referencia.
Puede crear una propiedad inmutable de dos maneras. Puede declarar el descriptor de acceso set como private. La
propiedad solo se puede establecer dentro del tipo, pero es inmutable a los consumidores. En su lugar puede
declarar solo el descriptor de acceso get, que hace que la propiedad sea inmutable en cualquier lugar excepto en el
constructor del tipo.
Cuando se declara un descriptor de acceso set privado, no se puede usar un inicializador de objeto para inicializar
la propiedad. Se debe utilizar un constructor o un mtodo factory.

Ejemplo
En el siguiente ejemplo se muestran dos maneras de implementar una clase inmutable que tenga propiedades
autoimplementadas. Cada forma declara una de las propiedades con un set privado y una de las propiedades
solamente con un get . La primera clase usa un constructor solo para inicializar las propiedades y la segunda clase
utiliza un mtodo factory esttico que llama a un constructor.

// This class is immutable. After an object is created,


// it cannot be modified from outside the class. It uses a
// constructor to initialize its properties.
class Contact
{
// Read-only properties.
public string Name { get; }
public string Address { get; private set; }

// Public constructor.
public Contact(string contactName, string contactAddress)
{
Name = contactName;
Address = contactAddress;
}
}

// This class is immutable. After an object is created,


// it cannot be modified from outside the class. It uses a
// static method and private constructor to initialize its properties.
public class Contact2
{
// Read-only properties.
public string Name { get; private set; }
public string Address { get; }

// Private constructor.
private Contact2(string contactName, string contactAddress)
{
Name = contactName;
Address = contactAddress;
}

// Public factory method.


// Public factory method.
public static Contact2 CreateContact(string name, string address)
{
return new Contact2(name, address);
}
}

public class Program


{
static void Main()
{
// Some simple data sources.
string[] names = {"Terry Adams","Fadi Fakhouri", "Hanying Feng",
"Cesar Garcia", "Debra Garcia"};
string[] addresses = {"123 Main St.", "345 Cypress Ave.", "678 1st Ave",
"12 108th St.", "89 E. 42nd St."};

// Simple query to demonstrate object creation in select clause.


// Create Contact objects by using a constructor.
var query1 = from i in Enumerable.Range(0, 5)
select new Contact(names[i], addresses[i]);

// List elements cannot be modified by client code.


var list = query1.ToList();
foreach (var contact in list)
{
Console.WriteLine("{0}, {1}", contact.Name, contact.Address);
}

// Create Contact2 objects by using a static factory method.


var query2 = from i in Enumerable.Range(0, 5)
select Contact2.CreateContact(names[i], addresses[i]);

// Console output is identical to query1.


var list2 = query2.ToList();

// List elements cannot be modified by client code.


// CS0272:
// list2[0].Name = "Eugene Zabokritski";

// Keep the console open in debug mode.


Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}

/* Output:
Terry Adams, 123 Main St.
Fadi Fakhouri, 345 Cypress Ave.
Hanying Feng, 678 1st Ave
Cesar Garcia, 12 108th St.
Debra Garcia, 89 E. 42nd St.
*/

El compilador crea campos de respaldo para cada propiedad autoimplementada. No se puede acceder a los
campos directamente desde el cdigo fuente.

Vea tambin
Propiedades
struct
Inicializadores de objeto y coleccin
Mtodos (Gua de programacin de C#)
03/10/2017 11 min to read Edit Online

Un mtodo es un bloque de cdigo que contiene una serie de instrucciones. Un programa hace que se ejecuten
las instrucciones al llamar al mtodo y especificando los argumentos de mtodo necesarios. En C#, todas las
instrucciones ejecutadas se realizan en el contexto de un mtodo. El mtodo Main es el punto de entrada para
cada aplicacin de C# y se llama mediante Common Language Runtime (CLR) cuando se inicia el programa.

NOTA
En este tema se analizan los mtodos denominados. Para obtener informacin sobre las funciones annimas, vea
Funciones annimas (Gua de programacin de C#).

Firmas de mtodo
Los mtodos se declaran en una clase o struct especificando el nivel de acceso, como public o private ,
modificadores opcionales como abstract o sealed , el valor de retorno, el nombre del mtodo y cualquier
parmetro de mtodo. Todas estas partes forman la firma del mtodo.

NOTA
Un tipo de valor devuelto de un mtodo no forma parte de la firma del mtodo con el objetivo de sobrecargar el mtodo.
Sin embargo, forma parte de la firma del mtodo al determinar la compatibilidad entre un delegado y el mtodo que
seala.

Los parmetros de mtodo se encierran entre parntesis y se separan por comas. Los parntesis vacos indican
que el mtodo no requiere parmetros. Esta clase contiene tres mtodos:

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 mtodos
Llamar a un mtodo en un objeto es como acceder a un campo. Despus del nombre del objeto, agregue un
punto, el nombre del mtodo y parntesis. Los argumentos se enumeran entre parntesis y estn separados por
comas. Los mtodos de la clase Motorcycle se pueden llamar 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 {0}", speed);
}
}

Parmetros de mtodos frente a Argumentos


La definicin del mtodo especifica los nombres y tipos de todos los parmetros necesarios. Si el cdigo de
llamada llama al mtodos, proporciona valores concretos denominados argumentos para cada parmetro. Los
argumentos deben ser compatibles con el tipo de parmetro, pero el nombre del argumento (si existe) utilizado
en el cdigo de llamada no tiene que ser el mismo que el parmetro con nombre definido en el mtodo. 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 evaulates 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 un tipo de valor se pasa a un mtodo, se pasa una copia en lugar del propio
objeto. Por lo tanto, los cambios realizados en el argumento no tienen ningn efecto en la copia original del
mtodo de llamada. Puede pasar un tipo de valor por referencia mediante la palabra clave ref. Para obtener ms
informacin, vea Pasar parmetros de tipo de valor (Gua de programacin de C#). Para obtener una lista de
tipos de valor integrados, vea Tabla de tipos de valor (Referencia de C#).
Cuando se pasa un objeto de un tipo de referencia a un mtodo, se pasa una referencia al objeto. Es decir, el
mtodo no recibe el objeto concreto, recibe un argumento que indica la ubicacin del objeto. Si cambia un
miembro del objeto mediante esta referencia, el cambio se refleja en el argumento del mtodo de llamada,
incluso si pasa el objeto por valor.
Crea un tipo de referencia mediante la palabra clave class , como se muestra en el siguiente ejemplo.

public class SampleRefType


{
public int value;
}

Ahora, si se pasa un objeto basado en este tipo a un mtodo, tambin se pasa una referencia al objeto. En el
ejemplo siguiente se pasa un objeto de tipo SampleRefType al mtodo 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;
}

Fundamentalmente, el ejemplo hace lo mismo que el ejemplo anterior en el que se pasa un argumento por valor
a un mtodo. Pero, debido a que se utiliza un tipo de referencia, el resultado es diferente. La modificacin que se
lleva a cabo en ModifyObject al campo value del parmetro, obj , tambin cambia el campo value del
argumento, rt , en el mtodo TestRefType . El mtodo TestRefType muestra 33 como salida.
Para obtener ms informacin sobre cmo pasar tipos de referencia por valor y por referencia, vea Pasar
parmetros Reference-Type (Gua de programacin de C#) y Tipos de referencia (Referencia de C#).

Valores devueltos
Los mtodos pueden devolver un valor al autor de llamada. Si el tipo de valor devuelto, el tipo enumerado antes
del nombre de mtodo, no es void , el mtodo puede devolver el valor mediante la utilizacin de la palabra clave
return . Una instruccin con la palabra clave return seguida de un valor que coincide con el tipo de valor
devuelto devolver este valor al autor de llamada del mtodo.
El valor puede devolverse al autor de la llamada mediante valor o, a partir de C# 7, mediante referencia. Los
valores se devuelven al autor de la llamada mediante referencia si la palabra clave ref se usa en la firma del
mtodo y sigue cada palabra clave return . Por ejemplo, la siguiente firma del mtodo y la instruccin return
indican que el mtodo devuelve nombres de variable estDistance mediante referencia al autor de la llamada.

public ref double GetEstimatedDistance()


{
return ref estDistance;
}

La palabra clave return tambin detiene la ejecucin del mtodo. Si el tipo de valor devuelto es void , una
instruccin return sin un valor tambin es til para detener la ejecucin del mtodo. Sin la palabra clave
return , el mtodo dejar de ejecutarse cuando alcance el final del bloque de cdigo. Los mtodos con un tipo
de valor devuelto no nulo son necesarios para usar la palabra clave return para devolver un valor. Por ejemplo,
estos dos mtodos 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 utilizar un valor devuelto de un mtodo, el mtodo de llamada puede usar la llamada de mtodo en
cualquier lugar; un valor del mismo tipo sera suficiente. Tambin puede asignar el valor devuelto a una variable.
Por ejemplo, los dos siguientes ejemplos de cdigo 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);

Usar una variable local, en este caso, result , para almacenar un valor es opcional. La legibilidad del cdigo
puede ser til, o puede ser necesaria si debe almacenar el valor original del argumento para todo el mbito del
mtodo.
Para usar un valor devuelto mediante referencia de un mtodo, debe declarar una variable local de tipo ref si
pretende modificar su valor. Por ejemplo, si el mtodo Planet.GetEstimatedDistance devuelve un valor Double
mediante referencia, puede definirlo como una variable local de tipo ref con cdigo como el siguiente:

ref int distance = plant

Devolver una matriz multidimensional de un mtodo, M , que modifica el contenido de la matriz no es necesario
si la funcin de llamada ha pasado la matriz a M . Puede devolver la matriz resultante de M para obtener un
estilo correcto o un flujo funcional de valores, pero no es necesario porque C# pasa todos los tipos de referencia
mediante valor, y el valor de una referencia de matriz es el puntero de la matriz. En el mtodo M , los cambios en
el contenido de la matriz los puede observar cualquier cdigo 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;
}
}
}

Para obtener ms informacin, consulta return.

Mtodos asincrnicos
Mediante la caracterstica asincrnica, puede invocar mtodos asincrnicos sin usar definiciones de llamada
explcitas ni dividir manualmente el cdigo en varios mtodos o expresiones lambda.
Si marca un mtodo con el modificador async , puede usar el operador await en el mtodo. Cuando el control
alcanza una expresin await en el mtodo asincrnico, el control se devuelve al autor de llamada y se progreso
del mtodo se suspende hasta que se completa la tarea esperada. Cuando se completa la tarea, la ejecucin
puede reanudarse en el mtodo.

NOTA
Un mtodo asincrnico vuelve al autor de llamada cuando encuentra el primer objeto esperado que an no se ha
completado o cuando llega al final del mtodo asincrnico, lo que ocurra primero.

Un mtodo asincrnico puede tener un tipo de valor devuelto de Task<TResult>, Task, o nulo. El tipo de valor
devuelto nulo se utiliza principalmente para definir controladores de eventos, donde se requiere un tipo de valor
devuelto nulo. No se puede esperar un mtodo asincrnico que devuelve nulo, y el autor de llamada de un
mtodo con tipo de devolucin nulo no puede capturar ninguna excepcin producida por este.
En el ejemplo siguiente, DelayAsync es un mtodo asincrnico con un tipo de valor devuelto de Task<TResult>.
DelayAsync tiene una instruccin return que devuelve un entero. Por lo tanto, la declaracin del mtodo de
DelayAsync debe tener un tipo de valor devuelto de Task<int> . Dado que el tipo de valor devuelto es Task<int>
, la evaluacin de la expresin await en DoSomethingAsync genera un entero, como se demuestra en la siguiente
instruccin: int result = await delayTask .
El mtodo startButton_Click es un ejemplo de un mtodo asincrnico con un tipo de valor devuelto nulo. Dado
que DoSomethingAsync es un mtodo asincrnico, la tarea de la llamada a DoSomethingAsync debe esperar, como
se muestra en la siguiente instruccin: await DoSomethingAsync(); . El mtodo startButton_Click debe definirse
con el modificador async porque el mtodo tiene una expresin await .
// using System.Diagnostics;
// using System.Threading.Tasks;

// This Click event is marked with the async modifier.


private async void startButton_Click(object sender, RoutedEventArgs e)
{
await DoSomethingAsync();
}

private 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();

Debug.WriteLine("Result: " + result);


}

private async Task<int> DelayAsync()


{
await Task.Delay(100);
return 5;
}

// Output:
// Result: 5

Un mtodo aisncrnico no puede declarar ningn parmetro ref u out , pero puede llamar a los mtodos que
tienen estos parmetros.
Para obtener ms informacin sobre los mtodos asincrnicos, vea Programacin asincrnica con Async y Await,
Flujo de control en programas asincrnicos y Tipos de valor devuelto de Async.

Definiciones de cuerpos de expresin


Es habitual tener definiciones de mtodo que simplemente hacen las devoluciones de forma inmediata con el
resultado de una expresin, o que tienen una sola instruccin como cuerpo del mtodo. Hay un acceso directo de
sintaxis para definir este mtodo 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 mtodo devuelve void o si es un mtodo asincrnico, el cuerpo del mtodo debe ser una expresin de
instruccin (igual que con las expresiones lambda). Para las propiedades y los indexadores, solo deben leerse, y
no usa la palabra clave de descriptor de acceso get .

Iteradores
Un iterador realiza una iteracin personalizada en una coleccin, como una lista o matriz. Un iterador utiliza la
instruccin yield return para devolver cada elemento de uno en uno. Cuando se alcanza la instruccin yield
return , se recuerda la ubicacin actual en el cdigo. La ejecucin se reinicia desde esa ubicacin la prxima vez
que se llama el iterador.
Llame a un iterador a partir del cdigo de cliente mediante una instruccin foreach .
El tipo de valor devuelto de un iterador puede ser IEnumerable, IEnumerable<T>, IEnumeratoro IEnumerator<T>.
Para obtener ms informacin, consulta Iteradores.

Especificacin del lenguaje C#


Para obtener ms informacin, consulte la Especificacin del lenguaje C#. La especificacin del lenguaje es la
fuente definitiva de la sintaxis y el uso de C#.

Vea tambin
Gua de programacin de C#
Clases y structs
Modificadores de acceso
Clases estticas y sus miembros
Herencia
Clases y miembros de clase abstractos y sellados
params
return
out
ref
Pasar parmetros
Funciones locales (Gua de programacin de C#)
03/10/2017 6 min to read Edit Online

A partir de C# 7, C# admite funciones locales. Las funciones locales son mtodos privados de un tipo que estn
anidados en otro miembro. Solo se pueden llamar desde su miembro contenedor. Las funciones locales se pueden
declarar en y llamar desde:
Mtodos, especialmente los mtodos de iterador y asincrnicos
Constructores
Descriptores de acceso de propiedad
Descriptores de acceso de un evento
Mtodos annimos
Expresiones lambda
Finalizadores
Otras funciones locales
En cambio, las funciones locales no se pueden declarar dentro de un miembro con forma de expresin.

NOTA
En algunos casos, puede usar una expresin lambda para implementar funcionalidad compatible tambin con una funcin
local. Para ver una comparacin, consulte Funciones locales frente a expresiones lambda.

Las funciones locales aclaran la intencin del cdigo. Cualquiera que lea el cdigo puede ver que solo el mtodo
que lo contiene puede llamar al mtodo. Para los proyectos de equipo, tambin hacen que sea imposible que otro
desarrollador llame errneamente al mtodo directamente desde cualquier otro punto de la clase o struct.

Sintaxis de funcin local


Una funcin local se define como un mtodo anidado dentro de un miembro contenedor. Su definicin tiene la
siguiente sintaxis:

<modifiers: async | unsafe> <return-type> <method-name> <parameter-list>

Las funciones locales pueden usar los modificadores async y unsafe.


Tenga en cuenta que todas las variables locales que se definen en el miembro contenedor, incluidos sus
parmetros de mtodo, son accesibles en la funcin local.
A diferencia de una definicin de mtodo, una definicin de funcin local no puede incluir los siguientes elementos:
El modificador de acceso de miembro. Dado que todas las funciones locales son privadas, incluido un
modificador de acceso, como la palabra clave private , se genera el error del compilador CS0106, "El
modificador 'private' no es vlido para este elemento".
La palabra clave static. Al incluir la palabra clave static , se genera el error del compilador CS0106, "El
modificador 'static' no es vlido para este elemento".
Adems, los atributos no se pueden aplicar a la funcin local o a sus parmetros y parmetros de tipo.
En el ejemplo siguiente, se define una funcin local denominada AppendPathSeparator que es privada a un mtodo
denominado GetText :

using System;
using System.IO;

class Example
{
static void Main()
{
string contents = GetText(@"C:\temp", "example.txt");
Console.WriteLine("Contents of the file:\n" + contents);
}

private static string GetText(string path, string filename)


{
var sr = File.OpenText(AppendPathSeparator(path) + filename);
var text = sr.ReadToEnd();
return text;

// Declare a local function.


string AppendPathSeparator(string filepath)
{
if (! filepath.EndsWith(@"\"))
filepath += @"\";

return filepath;
}
}
}

Excepciones y funciones locales


Una de las caractersticas tiles de las funciones locales es que pueden permitir que las excepciones aparezcan
inmediatamente. Para los iteradores de mtodo, las excepciones aparecen solo cuando la secuencia devuelta se
enumera y no cuando se recupera el iterador. Para los mtodos asincrnicos, las excepciones producidas en un
mtodo asincrnico se observan cuando se espera la tarea devuelta.
En el ejemplo siguiente, se define un mtodo OddSequence que enumera los nmeros impares entre un intervalo
especificado. Dado que pasa un nmero mayor de 100 al mtodo de enumerador OddSequence , el mtodo produce
una excepcin ArgumentOutOfRangeException. Como se muestra en el resultado del ejemplo, la excepcin aparece
solo cuando itera los nmeros, y no al recuperar el enumerador.
using System;
using System.Collections.Generic;

class Example
{
static void Main()
{
IEnumerable<int> ienum = OddSequence(50, 110);
Console.WriteLine("Retrieved enumerator...");

foreach (var i in ienum)


{
Console.Write($"{i} ");
}
}

public static IEnumerable<int> OddSequence(int start, int end)


{
if (start < 0 || start > 99)
throw new ArgumentOutOfRangeException("start must be between 0 and 99.");
if (end > 100)
throw new ArgumentOutOfRangeException("end must be less than or equal to 100.");
if (start >= end)
throw new ArgumentException("start must be less than end.");

for (int i = start; i <= end; i++)


{
if (i % 2 == 1)
yield return i;
}
}
}
// The example displays the following output:
// Retrieved enumerator...
//
// Unhandled Exception: System.ArgumentOutOfRangeException: Specified argument was out of the range of valid
values.
// Parameter name: end must be less than or equal to 100.
// at Sequence.<GetNumericRange>d__1.MoveNext() in Program.cs:line 23
// at Example.Main() in Program.cs:line 43

En su lugar, puede producir una excepcin al realizar la validacin y antes de recuperar el iterador al devolver el
iterador de una funcin local, como se muestra en el ejemplo siguiente.
using System;
using System.Collections.Generic;

class Example
{
static void Main()
{
IEnumerable<int> ienum = OddSequence(50, 110);
Console.WriteLine("Retrieved enumerator...");

foreach (var i in ienum)


{
Console.Write($"{i} ");
}
}

public static IEnumerable<int> OddSequence(int start, int end)


{
if (start < 0 || start > 99)
throw new ArgumentOutOfRangeException("start must be between 0 and 99.");
if (end > 100)
throw new ArgumentOutOfRangeException("end must be less than or equal to 100.");
if (start >= end)
throw new ArgumentException("start must be less than end.");

return GetOddSequenceEnumerator();

IEnumerable<int> GetOddSequenceEnumerator()
{
for (int i = start; i <= end; i++)
{
if (i % 2 == 1)
yield return i;
}
}
}
}
// The example displays the following output:
// Unhandled Exception: System.ArgumentOutOfRangeException: Specified argument was out of the range of valid
values.
// Parameter name: end must be less than or equal to 100.
// at Sequence.<GetNumericRange>d__1.MoveNext() in Program.cs:line 23
// at Example.Main() in Program.cs:line 43

Las funciones locales se pueden usar de forma similar, para controlar las excepciones fuera de la operacin
asincrnica. Normalmente, las excepciones producidas en el mtodo asincrnico requieren que examine las
excepciones internas de una excepcin AggregateException. Las funciones locales permiten que el cdigo genere
un error inmediato y permiten que la excepcin se produzca y observe de forma sincrnica.
En el ejemplo siguiente, se usa un mtodo asincrnico denominado GetMultipleAsync para pausar durante un
nmero especificado de segundos y se devuelve un valor que es un mltiplo aleatorio de ese nmero de segundos.
El retraso mximo es de 5 segundos; se produce una excepcin ArgumentOutOfRangeException si el valor es
mayor que 5. Como se muestra en el ejemplo siguiente, la excepcin que produce cuando se pasa un valor de 6 al
mtodo GetMultipleAsync se encapsula en una excepcin AggregateException despus de que el mtodo
GetMultipleAsync empiece a ejecutarse.
using System;
using System.Threading.Tasks;

class Example
{
static void Main()
{
int result = GetMultipleAsync(6).Result;
Console.WriteLine($"The returned value is {result:N0}");
}

static async Task<int> GetMultipleAsync(int secondsDelay)


{
Console.WriteLine("Executing GetMultipleAsync...");
if (secondsDelay < 0 || secondsDelay > 5)
throw new ArgumentOutOfRangeException("secondsDelay cannot exceed 5.");

await Task.Delay(secondsDelay * 1000);


return secondsDelay * new Random().Next(2,10);
}
}
// The example displays the following output:
// Executing GetMultipleAsync...
//
// Unhandled Exception: System.AggregateException:
// One or more errors occurred. (Specified argument was out of the range of valid values.
// Parameter name: secondsDelay cannot exceed 5.) --->
// System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
// Parameter name: secondsDelay cannot exceed 5.
// at Example.<GetMultiple>d__1.MoveNext() in Program.cs:line 17
// --- End of inner exception stack trace ---
// at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
// at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
// at Example.Main() in C:\Users\ronpet\Documents\Visual Studio 2017\Projects\local-
functions\async1\Program.cs:line 8

Igual que hemos hecho con el iterador de mtodo, podemos refactorizar el cdigo de este ejemplo para realizar la
validacin antes de llamar al mtodo asincrnico. Como se muestra en el resultado del ejemplo siguiente, la
excepcin ArgumentOutOfRangeException no se encapsula en una excepcin <x:System.AggregateException>.
using System;
using System.Threading.Tasks;

class Example
{
static void Main()
{
int result = GetMultiple(6).Result;
Console.WriteLine($"The returned value is {result:N0}");
}

static Task<int> GetMultiple(int secondsDelay)


{
if (secondsDelay < 0 || secondsDelay > 5)
throw new ArgumentOutOfRangeException("secondsDelay cannot exceed 5.");

return GetValueAsync();

async Task<int> GetValueAsync()


{
Console.WriteLine("Executing GetValueAsync...");
await Task.Delay(secondsDelay * 1000);
return secondsDelay * new Random().Next(2,10);
}
}
}
// The example displays the following output:
// Unhandled Exception: System.ArgumentOutOfRangeException:
// Specified argument was out of the range of valid values.
// Parameter name: secondsDelay cannot exceed 5.
// at Example.GetMultiple(Int32 secondsDelay) in Program.cs:line 17
// at Example.Main() in Program.cs:line 8

Vea tambin
Mtodos
Valores devueltos y variables locales de tipo ref
03/10/2017 7 min to read Edit Online

A partir de C# 7, C# admite los valores devueltos de referencia (valores devueltos de tipo ref). Un valor devuelto de
referencia permite que un mtodo devuelva una referencia a un objeto, en lugar de un valor, al autor de una
llamada. El autor de la llamada puede tratar el objeto devuelto como si se hubiera devuelto por valor o por
referencia. Un valor devuelto por referencia que el autor de la llamada trata como una referencia en lugar de un
valor es una variable local de tipo ref.

Qu es un valor devuelto de referencia?


La mayora de los desarrolladores estn familiarizados con pasar un argumento a un mtodo llamado por
referencia. La lista de argumentos de un mtodo llamado incluye un valor pasado por referencia y los cambios que
realiza en su valor el mtodo llamado se devuelven al autor de la llamada. Un valor devuelto de referencia es lo
contrario:
El valor devuelto del mtodo llamado, en lugar de un argumento que se le pasa, es una referencia.
El autor de la llamada, en lugar del mtodo llamado, puede modificar el valor devuelto por el mtodo.
En lugar de modificaciones al argumento que se reflejan en el estado del objeto en el autor de la llamada, las
modificaciones al valor devuelto del mtodo realizadas por el autor de la llamada se reflejan en el estado del
objeto cuyo mtodo se ha llamado.
Los valores devueltos de referencia pueden generar cdigo ms compacto, as como permitir que un objeto
exponga solo los elementos de datos individuales, como un elemento de matriz, que son de inters para el autor de
la llamada. Esto reduce la probabilidad de que el autor de la llamada modifique accidentalmente el estado del
objeto.
Hay algunas restricciones en el valor que un mtodo puede devolver como un valor devuelto de referencia. Se
incluyen los siguientes:
El valor devuelto no puede ser void . Al intentar definir un mtodo con un valor devuelto de referencia
void , se genera el error del compilador CS1547, "La palabra clave 'void' no se puede usar en este
contexto".
El valor devuelto no puede ser una variable local en el mtodo que lo devuelve; debe tener un mbito que
est fuera del mtodo que lo devuelve. Puede ser una instancia o un campo esttico de una clase, o puede
ser un argumento pasado al mtodo. Al intentar devolver una variable local, se genera el error del
compilador CS8168, "No se puede devolver por referencia la variable local 'obj' porque no es de tipo ref".
El valor devuelto no puede ser null . Si intenta devolver null , se genera el error del compilador CS8156,
"No se puede usar una expresin en este contexto porque no se puede devolver por referencia".
Si un mtodo con un valor devuelto de tipo ref necesita devolver un valor NULL, puede devolver un valor
NULL (sin instancia) para un tipo de referencia o un tipo que acepta valores NULL para un tipo de valor.
El valor devuelto no puede ser una constante, un miembro de enumeracin o una propiedad de una class
o struct . Si intenta devolver estos, se genera el error del compilador CS8156, "No se puede usar una
expresin en este contexto porque no se puede devolver por referencia".
Adems, puesto que un mtodo asincrnico puede volver antes de que haya terminado de ejecutarse, mientras su
valor devuelto siga siendo desconocido, los valores devueltos de referencia no se permiten en mtodos
asincrnicos.

Definir un valor devuelto de tipo ref


Para definir un valor devuelto de tipo ref, agregue la palabra clave ref al tipo de valor devuelto de la firma del
mtodo. Por ejemplo, la siguiente firma indica que la propiedad GetContactInformation devuelve una referencia a
un objeto Person al autor de la llamada:

public ref Person GetContactInformation(string fname, string lname);

Adems, el nombre del objeto devuelto por cada instruccin return en el cuerpo del mtodo debe ir precedido de
la palabra clave ref. Por ejemplo, la siguiente instruccin return devuelve un objeto Person denominado p por
referencia:

return ref p;

Usar un valor devuelto de tipo ref


El autor de una llamada puede controlar un valor devuelto de tipo ref de una de estas dos formas:
Como un valor normal devuelto por valor desde un mtodo. El autor de la llamada puede optar por omitir
que el valor devuelto es un valor devuelto de referencia. En este caso, los cambios realizados en el valor
devuelto por la llamada al mtodo no se reflejan en el estado del tipo llamado. Si el valor devuelto es un tipo
de valor, los cambios realizados en el valor devuelto por la llamada al mtodo no se reflejan en el estado del
tipo llamado.
Como un valor devuelto de referencia. El autor de la llamada debe definir la variable a la que se asigna el
valor devuelto de referencia como una variable local de tipo ref, y cualquier cambio en el valor devuelto por
la llamada al mtodo se refleja en el estado del tipo llamado.

Variables locales de tipo ref


Para controlar el valor devuelto de referencia como una referencia, el autor de la llamada debe declarar el valor
para que sea una variable local de tipo ref mediante la palabra clave ref . Por ejemplo, si el valor devuelto por el
mtodo Person.GetContactInfomation debe usarse como una referencia en lugar de un valor, la llamada al mtodo
aparece como:

ref Person p = ref contacts.GetContactInformation("Brandie", "Best");

Tenga en cuenta que la palabra clave ref se usa antes de la declaracin de variable local y antes de la llamada al
mtodo. Si no se incluyen ambas palabras clave ref en la asignacin y declaracin de variable, se produce el error
del compilador CS8172, "No se puede inicializar una variable por referencia con un valor".
Los cambios posteriores en el objeto Person devuelto por el mtodo se reflejan en el objeto contacts .
Si p no est definido como una variable local de tipo ref mediante la palabra clave ref , los cambios que realiza
en p el autor de la llamada no se reflejan en el objeto contacts .

Valores devueltos y variables locales de tipo ref: un ejemplo


En el ejemplo siguiente, se define una clase NumberStore que almacena una matriz de valores enteros. El mtodo
FindNumber devuelve por referencia el primer nmero que es mayor o igual que el nmero que se pasa como
argumento. Si ningn nmero es mayor o igual que el argumento, el mtodo devuelve el nmero en el ndice 0.

using System;

class NumberStore
{
int[] numbers = { 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023 };

public ref int FindNumber(int target)


{
for (int ctr = 0; ctr < numbers.Length; ctr++) {
if (target == numbers[ctr]) {
return ref numbers[ctr];
}
else if (ctr == numbers.Length - 1) {
return ref numbers[ctr];
}
else if (target < numbers[ctr]) {
if (ctr > 0 && target > numbers[ctr - 1])
return ref numbers[ctr];
else if (ctr == 0)
return ref numbers[0];
}
}
return ref numbers[0];
}

public override string ToString()


{
string retval = "";
for (int ctr = 0; ctr < numbers.Length; ctr++) {
retval += $"{numbers[ctr]} ";
}
return retval.Trim();
}
}

En el ejemplo siguiente, se llama al mtodo NumberStore.FindNumber para recuperar el primer valor que es mayor o
igual que 16. Despus, el autor de la llamada duplica el valor devuelto por el mtodo. Como se muestra en el
resultado del ejemplo, este cambio se refleja en el valor de los elementos de matriz de la instancia NumberStore .

using System;

public class Example


{
static void Main(string[] args)
{
var store = new NumberStore();
Console.WriteLine($"Original sequence: {store.ToString()}");
int number = 16;
ref var value = ref store.FindNumber(number);
value*=2;
Console.WriteLine($"New sequence: {store.ToString()}");
}
}
// The example displays the following output:
// Original sequence: 1 3 7 15 31 63 127 255 511 1023
// New sequence: 1 3 7 15 62 63 127 255 511 1023

Sin que se admitan los valores devueltos de referencia, este tipo de operacin se realiza normalmente devolviendo
el ndice del elemento de matriz junto con su valor. Despus, el autor de la llamada puede usar este ndice para
modificar el valor en una llamada al mtodo independiente. En cambio, el autor de la llamada tambin puede
modificar el ndice para tener acceso a otros valores de matriz y, posiblemente, modificarlos.
Vea tambin
ref (palabra clave)
Pasar parmetros (Gua de programacin de C#)
03/10/2017 1 min to read Edit Online

En C#, los argumentos se pueden pasar a parmetros por valor o por referencia. El paso de parmetros por
referencia permite a los miembros de funciones, mtodos, propiedades, indexadores, operadores y constructores
cambiar el valor de los parmetros y hacer que ese cambio persista en el entorno de la llamada. Para pasar un
parmetro por referencia, use una de las palabras clave ref o out . En los ejemplos de este tema, para simplificar,
solo se usa la palabra clave ref . Para obtener ms informacin sobre la diferencia entre ref y out , vea ref, out
y Pasar matrices mediante Ref y Out.
En el ejemplo siguiente se muestra la diferencia entre los parmetros de valor y de referencia.

class Program
{
static void Main(string[] args)
{
int arg;

// Passing by value.
// The value of arg in Main is not changed.
arg = 4;
squareVal(arg);
Console.WriteLine(arg);
// Output: 4

// Passing by reference.
// The value of arg in Main is changed.
arg = 4;
squareRef(ref arg);
Console.WriteLine(arg);
// Output: 16
}

static void squareVal(int valParameter)


{
valParameter *= valParameter;
}

// Passing by reference
static void squareRef(ref int refParameter)
{
refParameter *= refParameter;
}
}

Para obtener ms informacin, vea los temas siguientes:


Pasar parmetros de tipo de valor
Pasar parmetros Reference-Type

Especificacin del lenguaje C#


Para obtener ms informacin, consulte la Especificacin del lenguaje C#. La especificacin del lenguaje es la
fuente definitiva de la sintaxis y el uso de C#.
Vea tambin
Gua de programacin de C#
Mtodos
Pasar parmetros de tipo de valor (Gua de
programacin de C#)
03/10/2017 3 min to read Edit Online

Una variable tipo de valor contiene sus datos directamente, en oposicin a la variable tipo de referencia, que
contiene una referencia a sus datos. Pasar una variable tipo de valor a un mtodo en funcin del valor significa
pasar una copia de la variable al mtodo. Ningn cambio realizado en el parmetro dentro del mtodo afecta a los
datos originales almacenados en la variable de argumentos. Si desea que el mtodo al que se llama cambie el valor
del parmetro, debe pasarlo en funcin de la referencia, con la palabra clave ref o out. Para simplificar, en el
ejemplo siguiente se usa ref .

Pasar tipos de valor en funcin del valor


En el ejemplo siguiente se muestra cmo pasar los parmetros de tipo de valor en funcin del valor. La variable n
se pasa en funcin del valor al mtodo SquareIt . Los cambios que tienen lugar dentro del mtodo no tienen
ningn efecto en el valor original de la variable.

class PassingValByVal
{
static void SquareIt(int x)
// The parameter x is passed by value.
// Changes to x will not affect the original value of x.
{
x *= x;
System.Console.WriteLine("The value inside the method: {0}", x);
}
static void Main()
{
int n = 5;
System.Console.WriteLine("The value before calling the method: {0}", n);

SquareIt(n); // Passing the variable by value.


System.Console.WriteLine("The value after calling the method: {0}", n);

// Keep the console window open in debug mode.


System.Console.WriteLine("Press any key to exit.");
System.Console.ReadKey();
}
}
/* Output:
The value before calling the method: 5
The value inside the method: 25
The value after calling the method: 5
*/

La variable n es un tipo de valor. Contiene sus datos, el valor 5 . Cuando se invoca SquareIt , el contenido de n
se copia en el parmetro x , que se multiplica dentro del mtodo. En Main , sin embargo, el valor de n es el
mismo despus de llamar al mtodo SquareIt que el que era antes. El cambio que tiene lugar dentro del mtodo
solo afecta a la variable local x .

Pasar tipos de valor en funcin de la referencia


El ejemplo siguiente es el mismo que el anterior, salvo que el argumento se pasa como un parmetro ref . El valor
del argumento subyacente, n , se cambia cuando se modifica x en el mtodo.

class PassingValByRef
{
static void SquareIt(ref int x)
// The parameter x is passed by reference.
// Changes to x will affect the original value of x.
{
x *= x;
System.Console.WriteLine("The value inside the method: {0}", x);
}
static void Main()
{
int n = 5;
System.Console.WriteLine("The value before calling the method: {0}", n);

SquareIt(ref n); // Passing the variable by reference.


System.Console.WriteLine("The value after calling the method: {0}", n);

// Keep the console window open in debug mode.


System.Console.WriteLine("Press any key to exit.");
System.Console.ReadKey();
}
}
/* Output:
The value before calling the method: 5
The value inside the method: 25
The value after calling the method: 25
*/

En este ejemplo, no es el valor de n el que se pasa, sino una referencia a n . El parmetro x no es un entero; se
trata de una referencia a int , en este caso, una referencia a n . Por tanto, cuando x se multiplica dentro del
mtodo, lo que realmente se multiplica es a lo que x hace referencia, n .

Intercambiar tipos de valor


Un ejemplo comn de modificacin de valores de argumentos es un mtodo de intercambio, donde se pasan dos
variables al mtodo, y el mtodo intercambia su contenido. Debe pasar los argumentos al mtodo de intercambio
en funcin de la referencia. De lo contrario, se intercambian copias locales de los parmetros dentro del mtodo, y
no se produce ningn cambio en el mtodo de llamada. En el ejemplo siguiente se intercambian valores enteros.

static void SwapByRef(ref int x, ref int y)


{
int temp = x;
x = y;
y = temp;
}

Al llamar al mtodo SwapByRef , use la palabra clave ref en la llamada, como se muestra en el ejemplo siguiente.
static void Main()
{
int i = 2, j = 3;
System.Console.WriteLine("i = {0} j = {1}" , i, j);

SwapByRef (ref i, ref j);

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

// Keep the console window open in debug mode.


System.Console.WriteLine("Press any key to exit.");
System.Console.ReadKey();
}
/* Output:
i = 2 j = 3
i = 3 j = 2
*/

Vea tambin
Gua de programacin de C#
Pasar parmetros
Pasar parmetros Reference-Type
Pasar parmetros Reference-Type (Gua de
programacin de C#)
03/10/2017 4 min to read Edit Online

Una variable de un tipo de referencia no contiene sus datos directamente, contiene una referencia a sus datos. Al
pasar un parmetro de tipo de referencia por valor, es posible cambiar los datos a los que apunta el tipo de
referencia, como el valor de un miembro de clase. En cambio, no se puede cambiar el valor de la propia referencia;
es decir, no puede usar la misma referencia para asignar memoria para una nueva clase y hacer que persista fuera
del bloque. Para ello, pase el parmetro mediante las palabras clave ref u out. Para simplificar, en el ejemplo
siguiente se usa ref .

Pasar tipos de referencia en funcin del valor


En el ejemplo siguiente, se muestra cmo pasar un parmetro de tipo de referencia, arr , en funcin del valor a un
mtodo, Change . Dado que el parmetro es una referencia a arr , es posible cambiar los valores de los elementos
de matriz. En cambio, el intento de volver a asignar el parmetro a otra ubicacin de memoria solo funciona
dentro del mtodo y no afecta a la variable original, arr .

class PassingRefByVal
{
static void Change(int[] pArray)
{
pArray[0] = 888; // This change affects the original element.
pArray = new int[5] {-3, -1, -2, -3, -4}; // This change is local.
System.Console.WriteLine("Inside the method, the first element is: {0}", pArray[0]);
}

static void Main()


{
int[] arr = {1, 4, 5};
System.Console.WriteLine("Inside Main, before calling the method, the first element is: {0}", arr
[0]);

Change(arr);
System.Console.WriteLine("Inside Main, after calling the method, the first element is: {0}", arr [0]);
}
}
/* Output:
Inside Main, before calling the method, the first element is: 1
Inside the method, the first element is: -3
Inside Main, after calling the method, the first element is: 888
*/

En el ejemplo anterior, la matriz, arr , que es un tipo de referencia, se pasa al mtodo sin el parmetro ref . En tal
caso, se pasa al mtodo una copia de la referencia, que apunta a arr . El resultado muestra que es posible que el
mtodo cambie el contenido de un elemento de matriz, en este caso de 1 a 888 . En cambio, si se asigna una
nueva porcin de memoria al usar el operador new dentro del mtodo Change , la variable pArray hace referencia
a una nueva matriz. Por tanto, cualquier cambio que hubiese despus no afectar a la matriz original, arr , que se
ha creado dentro de Main . De hecho, se crean dos matrices en este ejemplo, una dentro de Main y otra dentro del
mtodo Change .

Pasar tipos de referencia en funcin de la referencia


El ejemplo siguiente es el mismo que el anterior, salvo que la palabra clave ref se agrega a la llamada y al
encabezado de mtodo. Los cambios que tengan lugar en el mtodo afectan a la variable original en el programa
que realiza la llamada.

class PassingRefByRef
{
static void Change(ref int[] pArray)
{
// Both of the following changes will affect the original variables:
pArray[0] = 888;
pArray = new int[5] {-3, -1, -2, -3, -4};
System.Console.WriteLine("Inside the method, the first element is: {0}", pArray[0]);
}

static void Main()


{
int[] arr = {1, 4, 5};
System.Console.WriteLine("Inside Main, before calling the method, the first element is: {0}", arr[0]);

Change(ref arr);
System.Console.WriteLine("Inside Main, after calling the method, the first element is: {0}", arr[0]);
}
}
/* Output:
Inside Main, before calling the method, the first element is: 1
Inside the method, the first element is: -3
Inside Main, after calling the method, the first element is: -3
*/

Todos los cambios que tienen lugar dentro del mtodo afectan a la matriz original en Main . De hecho, la matriz
original se reasigna mediante el operador new . Por tanto, despus de llamar al mtodo Change , cualquier
referencia a arr apunta a la matriz de cinco elementos, que se crea en el mtodo Change .

Intercambiar dos cadenas


Intercambiar cadenas es un buen ejemplo de pasar parmetros de tipo de referencia en funcin de la referencia. En
el ejemplo, se inicializan dos cadenas, str1 y str2 , en Main y se pasan al mtodo SwapStrings como
parmetros modificados por la palabra clave ref . Las dos cadenas se intercambian dentro del mtodo y tambin
dentro de Main .
class SwappingStrings
{
static void SwapStrings(ref string s1, ref string s2)
// The string parameter is passed by reference.
// Any changes on parameters will affect the original variables.
{
string temp = s1;
s1 = s2;
s2 = temp;
System.Console.WriteLine("Inside the method: {0} {1}", s1, s2);
}

static void Main()


{
string str1 = "John";
string str2 = "Smith";
System.Console.WriteLine("Inside Main, before swapping: {0} {1}", str1, str2);

SwapStrings(ref str1, ref str2); // Passing strings by reference


System.Console.WriteLine("Inside Main, after swapping: {0} {1}", str1, str2);
}
}
/* Output:
Inside Main, before swapping: John Smith
Inside the method: Smith John
Inside Main, after swapping: Smith John
*/

En este ejemplo, los parmetros tienen que pasarse en funcin de la referencia para afectar a las variables en el
programa que realiza la llamada. Si quita la palabra clave ref tanto del encabezado de mtodo como de la
llamada al mtodo, no se llevar a cabo ningn cambio en el programa que realiza la llamada.
Para obtener ms informacin sobre las cadenas, vea string.

Vea tambin
Gua de programacin de C#
Pasar parmetros
Pasar matrices mediante Ref y Out
ref
Tipos de referencia
Cmo: Saber las diferencias entre pasar a un mtodo
un struct y una referencia a clase (Gua de
programacin de C#)
03/10/2017 2 min to read Edit Online

En el ejemplo siguiente se muestra cmo pasar un struct a un mtodo es diferente de pasar una instancia de clase a
un mtodo. En el ejemplo, los dos argumentos (struct e instancia de clase) se pasan mediante valor, y ambos
mtodos cambian el valor de un campo del argumento. En cambio, los resultados de los dos mtodos no son los
mismos porque lo que se pasa cuando pasa un struct difiere de lo que se pasa cuando pasa una instancia de una
clase.
Como un struct es un tipo de valor, cuando pasa un struct mediante valor a un mtodo, el mtodo recibe y funciona
en una copia del argumento struct. El mtodo no tiene acceso al struct original en el mtodo de llamada y, por lo
tanto, no puede cambiarlo de ninguna manera. El mtodo solo puede cambiar la copia.
Una instancia de clase es un tipo de referencia, no un tipo de valor. Cuando un tipo de referencia se pasa mediante
valor a un mtodo, el mtodo recibe una copia de la referencia a la instancia de clase. Es decir, el mtodo recibe una
copia de la direccin de la instancia, no una copia de la propia instancia. La instancia de clase en el mtodo de
llamada tiene una direccin, el parmetro en el mtodo que se ha llamado tiene una copia de la direccin, y ambas
direcciones hacen referencia al mismo objeto. Como el parmetro solo contiene una copia de la direccin, el
mtodo al que se ha llamado no puede cambiar la direccin de la instancia de clase en el mtodo de llamada. En
cambio, el mtodo al que se ha llamado puede usar la direccin para tener acceso a los miembros de clase que la
direccin original y la copia hacen referencia. Si el mtodo al que se ha llamado cambia un miembro de clase, la
instancia de clase original en el mtodo de llamada tambin cambia.
En el resultado del ejemplo siguiente se ilustra la diferencia. El valor del campo willIChange de la instancia de clase
se cambia mediante la llamada al mtodo ClassTaker porque el mtodo usa la direccin en el parmetro para
buscar el campo especificado de la instancia de clase. El campo willIChange del struct en el mtodo de llamada no
se cambia mediante la llamada al mtodo StructTaker porque el valor del argumento es una copia del propio
struct, no una copia de su direccin. StructTaker cambia la copia, y la copia se pierde cuando se completa la
llamada a StructTaker .

Ejemplo
class TheClass
{
public string willIChange;
}

struct TheStruct
{
public string willIChange;
}

class TestClassAndStruct
{
static void ClassTaker(TheClass c)
{
c.willIChange = "Changed";
}

static void StructTaker(TheStruct s)


{
s.willIChange = "Changed";
}

static void Main()


{
TheClass testClass = new TheClass();
TheStruct testStruct = new TheStruct();

testClass.willIChange = "Not Changed";


testStruct.willIChange = "Not Changed";

ClassTaker(testClass);
StructTaker(testStruct);

Console.WriteLine("Class field = {0}", testClass.willIChange);


Console.WriteLine("Struct field = {0}", testStruct.willIChange);

// Keep the console window open in debug mode.


Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
/* Output:
Class field = Changed
Struct field = Not Changed
*/

Vea tambin
Gua de programacin de C#
Clases
Structs
Pasar parmetros
Variables locales con asignacin implcita de tipos
(Gua de programacin de C#)
03/10/2017 4 min to read Edit Online

Las variables locales pueden declararse sin proporcionar un tipo explcito. La palabra clave var indica al
compilador que infiera el tipo de la variable a partir de la expresin de la derecha de la instruccin de inicializacin.
El tipo inferido puede ser un tipo integrado, un tipo annimo, un tipo definido por el usuario o un tipo definido en
la biblioteca de clases .NET Framework. Para obtener ms informacin sobre cmo inicializar las matrices con var ,
vea Matrices con tipo implcito.
Los ejemplos siguientes muestran distintas formas en que se pueden declarar variables locales con var :

// i is compiled as an int
var i = 5;

// s is compiled as a string
var s = "Hello";

// a is compiled as int[]
var a = new[] { 0, 1, 2 };

// expr is compiled as IEnumerable<Customer>


// or perhaps IQueryable<Customer>
var expr =
from c in customers
where c.City == "London"
select c;

// anon is compiled as an anonymous type


var anon = new { Name = "Terry", Age = 34 };

// list is compiled as List<int>


var list = new List<int>();

Es importante comprender que la palabra clave var no significa "variant" ni indica que la variable est dbilmente
tipada o est enlazada en tiempo de ejecucin. Solo significa que el compilador determina y asigna el tipo ms
adecuado.
La palabra clave var se puede usar en los contextos siguientes:
En variables locales (variables declaradas en el mbito del mtodo), tal y como se muestra en el ejemplo
anterior.
En una instruccin de inicializacin for.

for(var x = 1; x < 10; x++)

En una instruccin de inicializacin foreach.

foreach(var item in list){...}

En una instruccin using.


using (var file = new StreamReader("C:\\myfile.txt")) {...}

Para obtener ms informacin, vea Cmo: Usar matrices y variables locales con tipo implcito en expresiones de
consulta (Gua de programacin de C#).

var y tipos annimos


En muchos casos, el uso de var es opcional y es simplemente una comodidad sintctica. Pero cuando una variable
se inicializa con un tipo annimo, la variable se debe declarar como var si necesita acceder ms adelante a las
propiedades del objeto. Se trata de un escenario comn en expresiones de consulta LINQ. Para obtener ms
informacin, consulte Anonymous Types (Tipos annimos [Gua de programacin de C#]).
Desde el punto de vista del cdigo fuente, un tipo annimo no tiene nombre. Por lo tanto, si una variable de
consulta se ha inicializado con var , la nica manera de tener acceso a las propiedades de la secuencia de objetos
devuelta consiste en usar var como el tipo de la variable de iteracin en la instruccin foreach .

class ImplicitlyTypedLocals2
{
static void Main()
{
string[] words = { "aPPLE", "BlUeBeRrY", "cHeRry" };

// If a query produces a sequence of anonymous types,


// then use var in the foreach statement to access the properties.
var upperLowerWords =
from w in words
select new { Upper = w.ToUpper(), Lower = w.ToLower() };

// Execute the query


foreach (var ul in upperLowerWords)
{
Console.WriteLine("Uppercase: {0}, Lowercase: {1}", ul.Upper, ul.Lower);
}
}
}
/* Outputs:
Uppercase: APPLE, Lowercase: apple
Uppercase: BLUEBERRY, Lowercase: blueberry
Uppercase: CHERRY, Lowercase: cherry
*/

Comentarios
Las siguientes restricciones se aplican a las declaraciones de variable con tipo implcito:
var solo se puede usar cuando una variable local se declara e inicializa en la misma instruccin; la variable
no se puede inicializar en null ni en un grupo de mtodos o una funcin annima.
var no se puede usar en campos en el mbito de clase.
Las variables declaradas con var no se pueden usar en la expresin de inicializacin. En otras palabras, esta
expresin es vlida : int i = (i = 20); , pero esta expresin genera un error en tiempo de compilacin:
var i = (i = 20);

No se pueden inicializar varias variables con tipo implcito en la misma instruccin.


Si en el mbito se encuentra un tipo con nombre var , la palabra clave var se resolver en ese nombre de
tipo y no se tratar como parte de una declaracin de variable local con tipo implcito.
Es posible que var tambin pueda resultar til con expresiones de consulta en las que es difcil determinar el tipo
construido exacto de la variable de consulta. Esto puede ocurrir con las operaciones de agrupamiento y ordenacin.
La palabra clave var tambin puede ser til cuando resulte tedioso escribir el tipo especfico de la variable en el
teclado, o sea obvio o no aumente la legibilidad del cdigo. Un ejemplo en el que var resulta til de esta manera
es cuando se usa con tipos genricos anidados, como los que se emplean con las operaciones de grupo. En la
siguiente consulta, el tipo de la variable de consulta es IEnumerable<IGrouping<string, Student>> . Siempre que
usted y otras personas que deban mantener el cdigo comprendan esto, no hay ningn problema con el uso de
tipos implcitos por comodidad y brevedad.

// Same as previous example except we use the entire last name as a key.
// Query variable is an IEnumerable<IGrouping<string, Student>>
var studentQuery3 =
from student in students
group student by student.Last;

Pero el uso de var supone al menos la posibilidad de que el cdigo sea ms difcil de comprender para otros
programadores. Por ese motivo, la documentacin de C# por lo general solo usa var cuando es necesario.

Vea tambin
Referencia de C#
Implicitly Typed Arrays (Matrices con tipo implcito [Gua de programacin de C#])
Cmo: Usar matrices y variables locales con tipo implcito en expresiones de consulta (Gua de programacin de
C#)
Anonymous Types (Tipos annimos [Gua de programacin de C#])
Inicializadores de objeto y de coleccin
var
Expresiones de consulta LINQ
LINQ (Language-Integrated Query) (Language Integrated Query [LINQ])
for
foreach, in
using (instruccin)
Cmo: Usar matrices y variables locales con tipo
implcito en expresiones de consulta (Gua de
programacin de C#)
03/10/2017 2 min to read Edit Online

Puede usar variables locales con tipo implcito siempre que quiera que el compilador determine el tipo de una
variable local. Debe usar variables locales con tipo implcito para almacenar tipos annimos, que a menudo se usan
en las expresiones de consulta. En los ejemplos siguientes, se muestran los usos obligatorios y opcionales de las
variables locales con tipo implcito en las consultas.
Las variables locales con tipo implcito se declaran mediante la palabra clave contextual var. Para obtener ms
informacin, vea Variables locales con asignacin implcita de tipos y Matrices con asignacin implcita de tipos.

Ejemplo
En el ejemplo siguiente, se muestra un escenario comn en el que la palabra clave var es necesaria: una expresin
de consulta que genera una secuencia de tipos annimos. En este escenario, la variable de consulta y la variable de
iteracin en la instruccin foreach deben escribirse de forma implcita mediante el uso de var porque no se tiene
acceso a un nombre de tipo para el tipo annimo. Para obtener ms informacin sobre los tipos annimos, vea
Tipos annimos.

private static void QueryNames(char firstLetter)


{
// Create the query. Use of var is required because
// the query produces a sequence of anonymous types:
// System.Collections.Generic.IEnumerable<????>.
var studentQuery =
from student in students
where student.FirstName[0] == firstLetter
select new { student.FirstName, student.LastName };

// Execute the query and display the results.


foreach (var anonType in studentQuery)
{
Console.WriteLine("First = {0}, Last = {1}", anonType.FirstName, anonType.LastName);
}
}

Ejemplo
En el ejemplo siguiente, se usa la palabra clave var en una situacin similar, pero en la que el uso de var es
opcional. Dado que student.LastName es una cadena, la ejecucin de la consulta devuelve una secuencia de
cadenas. Por tanto, el tipo de queryID podra declararse como System.Collections.Generic.IEnumerable<string> en
lugar de var . La palabra clave var se usa por comodidad. En el ejemplo, la variable de iteracin en la instruccin
foreach se escribe de forma explcita como una cadena, pero se podra declarar mediante var . Dado que el tipo
de la variable de iteracin no es un tipo annimo, el uso de var es opcional, no es obligatorio. Recuerde que var
no es un tipo, sino una instruccin para que el compilador deduzca y asigne el tipo.
// Variable queryID could be declared by using
// System.Collections.Generic.IEnumerable<string>
// instead of var.
var queryID =
from student in students
where student.ID > 111
select student.LastName;

// Variable str could be declared by using var instead of string.


foreach (string str in queryID)
{
Console.WriteLine("Last name: {0}", str);
}

Vea tambin
Gua de programacin de C#
Mtodos de extensin
LINQ (Language-Integrated Query)
var
Expresiones de consulta LINQ
Mtodos de extensin (Gua de programacin de C#)
03/10/2017 8 min to read Edit Online

Los mtodos de extensin permiten "agregar" mtodos a los tipos existentes sin crear un nuevo tipo derivado,
recompilar o modificar de otra manera el tipo original. Los mtodos de extensin son una clase especial de
mtodo esttico, pero se les llama como si fueran mtodos de instancia en el tipo extendido. En el caso del cdigo
de cliente escrito en C#, F# y Visual Basic, no existe ninguna diferencia aparente entre llamar a un mtodo de
extensin y llamar a los mtodos realmente definidos en un tipo.
Los mtodos de extensin ms comunes son los operadores de consulta LINQ estndar, que agregan funciones de
consulta a los tipos System.Collections.IEnumerable y System.Collections.Generic.IEnumerable<T> existentes. Para
usar los operadores de consulta estndar, inclyalos primero en el mbito con una directiva using System.Linq . A
partir de ese momento, cualquier tipo que implemente IEnumerable<T> parecer tener mtodos de instancia
como GroupBy, OrderBy, Average, etc. Puede ver estos mtodos adicionales en la finalizacin de instrucciones de
IntelliSense al escribir "punto" despus de una instancia de un tipo IEnumerable<T>, como List<T> o Array.
En el ejemplo siguiente se muestra cmo llamar al mtodo OrderBy de operador de consulta estndar en una
matriz de enteros. La expresin entre parntesis es una expresin lambda. Muchos operadores de consulta
estndar toman expresiones lambda como parmetros, pero no es un requisito para los mtodos de extensin.
Para obtener ms informacin, vea Lambda Expressions (Expresiones lambda).

class ExtensionMethods2
{

static void Main()


{
int[] ints = { 10, 45, 15, 39, 21, 26 };
var result = ints.OrderBy(g => g);
foreach (var i in result)
{
System.Console.Write(i + " ");
}
}
}
//Output: 10 15 21 26 39 45

Los mtodos de extensin se definen como mtodos estticos, pero se les llama usando la sintaxis de mtodo de
instancia. El primer parmetro especifica en qu tipo funciona el mtodo, y el parmetro est precedido del
modificador this. Los mtodos de extensin nicamente se encuentran dentro del mbito cuando el espacio de
nombres se importa explcitamente en el cdigo fuente con una directiva using .
En el ejemplo siguiente se muestra un mtodo de extensin definido para la clase System.String. Observe que se
define dentro de una clase esttica no anidada y no genrica:
namespace ExtensionMethods
{
public static class MyExtensions
{
public static int WordCount(this String str)
{
return str.Split(new char[] { ' ', '.', '?' },
StringSplitOptions.RemoveEmptyEntries).Length;
}
}
}

El mtodo de extensin WordCount se puede incluir en el mbito con esta directiva using :

using ExtensionMethods;

Tambin se le puede llamar desde una aplicacin con esta sintaxis:

string s = "Hello Extension Methods";


int i = s.WordCount();

En el cdigo, el mtodo de extensin se invoca con la sintaxis de mtodo de instancia. Sin embargo, el lenguaje
intermedio (IL) generado por el compilador convierte el cdigo en una llamada en el mtodo esttico. Por lo tanto,
el principio de encapsulacin no se infringe realmente. De hecho, los mtodos de extensin no pueden tener
acceso a las variables privadas en el tipo que extienden.
Para obtener ms informacin, vea How to: Implement and Call a Custom Extension Method (Cmo: Implementar
e invocar un mtodo de extensin personalizado).
En general, probablemente se llamar a mtodos de extensin con mucha ms frecuencia de la que se
implementarn mtodos propios. Dado que los mtodos de extensin se llaman con la sintaxis de mtodo de
instancia, no se requieren conocimientos especiales para usarlos desde el cdigo de cliente. Para habilitar los
mtodos de extensin para un tipo determinado, basta con agregar una directiva using para el espacio de
nombres en el que se definen los mtodos. Por ejemplo, para usar los operadores de consulta estndar, agregue
esta directiva using al cdigo:

using System.Linq;

(Puede que haya que agregar tambin una referencia a System.Core.dll). Observar que los operadores de
consulta estndar aparecen ahora en IntelliSense como mtodos adicionales disponibles para la mayora de los
tipos IEnumerable<T>.

NOTA
Aunque los operadores de consulta estndar no aparezcan en IntelliSense para String, siguen estando disponibles.

Enlazar mtodos de extensin en tiempo de compilacin


Se pueden usar mtodos de extensin para ampliar una clase o interfaz, pero no para invalidarlas. Nunca se
llamar a un mtodo de extensin con el mismo nombre y signatura que un mtodo de interfaz o clase. En tiempo
de compilacin, los mtodos de extensin siempre tienen menos prioridad que los mtodos de instancia definidos
en el propio tipo. En otras palabras, si un tipo tiene un mtodo denominado Process(int i) y hay un mtodo de
extensin con la misma signatura, el compilador siempre se enlazar al mtodo de instancia. Cuando el
compilador encuentra una invocacin de mtodo, primero busca una coincidencia en los mtodos de instancia del
tipo. Si no la hay, buscar cualquier mtodo de extensin definido para el tipo y se enlazar al primer mtodo de
extensin que encuentre. En el ejemplo siguiente se muestra cmo determina el compilador a qu mtodo de
extensin o de instancia enlazarse.

Ejemplo
En el ejemplo siguiente se muestran las reglas que el compilador de C# sigue para determinar si se va a enlazar
una llamada a mtodo a un mtodo de instancia del tipo o a un mtodo de extensin. La clase esttica Extensions
contiene mtodos de extensin definidos para cualquier tipo que implemente IMyInterface . Las clases A , B y C
implementan la interfaz.
Nunca se llama al mtodo de extensin MethodB , porque su nombre y signatura coinciden exactamente con los
mtodos ya implementados por las clases.
Si el compilador no encuentra un mtodo de instancia con una signatura coincidente, se enlazar a un mtodo de
extensin coincidente, si existe.

// Define an interface named IMyInterface.


namespace DefineIMyInterface
{
using System;

public interface IMyInterface


{
// Any class that implements IMyInterface must define a method
// that matches the following signature.
void MethodB();
}
}

// Define extension methods for IMyInterface.


namespace Extensions
{
using System;
using DefineIMyInterface;

// The following extension methods can be accessed by instances of any


// class that implements IMyInterface.
public static class Extension
{
public static void MethodA(this IMyInterface myInterface, int i)
{
Console.WriteLine
("Extension.MethodA(this IMyInterface myInterface, int i)");
}

public static void MethodA(this IMyInterface myInterface, string s)


{
Console.WriteLine
("Extension.MethodA(this IMyInterface myInterface, string s)");
}

// This method is never called in ExtensionMethodsDemo1, because each


// of the three classes A, B, and C implements a method named MethodB
// that has a matching signature.
public static void MethodB(this IMyInterface myInterface)
{
Console.WriteLine
("Extension.MethodB(this IMyInterface myInterface)");
}
}
}
// Define three classes that implement IMyInterface, and then use them to test
// the extension methods.
namespace ExtensionMethodsDemo1
{
using System;
using Extensions;
using DefineIMyInterface;

class A : IMyInterface
{
public void MethodB() { Console.WriteLine("A.MethodB()"); }
}

class B : IMyInterface
{
public void MethodB() { Console.WriteLine("B.MethodB()"); }
public void MethodA(int i) { Console.WriteLine("B.MethodA(int i)"); }
}

class C : IMyInterface
{
public void MethodB() { Console.WriteLine("C.MethodB()"); }
public void MethodA(object obj)
{
Console.WriteLine("C.MethodA(object obj)");
}
}

class ExtMethodDemo
{
static void Main(string[] args)
{
// Declare an instance of class A, class B, and class C.
A a = new A();
B b = new B();
C c = new C();

// For a, b, and c, call the following methods:


// -- MethodA with an int argument
// -- MethodA with a string argument
// -- MethodB with no argument.

// A contains no MethodA, so each call to MethodA resolves to


// the extension method that has a matching signature.
a.MethodA(1); // Extension.MethodA(object, int)
a.MethodA("hello"); // Extension.MethodA(object, string)

// A has a method that matches the signature of the following call


// to MethodB.
a.MethodB(); // A.MethodB()

// B has methods that match the signatures of the following


// method calls.
b.MethodA(1); // B.MethodA(int)
b.MethodB(); // B.MethodB()

// B has no matching method for the following call, but


// class Extension does.
b.MethodA("hello"); // Extension.MethodA(object, string)

// C contains an instance method that matches each of the following


// method calls.
c.MethodA(1); // C.MethodA(object)
c.MethodA("hello"); // C.MethodA(object)
c.MethodB(); // C.MethodB()
}
}
}
/* Output:
Extension.MethodA(this IMyInterface myInterface, int i)
Extension.MethodA(this IMyInterface myInterface, string s)
A.MethodB()
B.MethodA(int i)
B.MethodB()
Extension.MethodA(this IMyInterface myInterface, string s)
C.MethodA(object obj)
C.MethodA(object obj)
C.MethodB()
*/

Instrucciones generales
En general, recomendamos que se implementen mtodos de extensin con moderacin y nicamente cuando sea
necesario. Siempre que sea posible, el cdigo de cliente que debe extender un tipo existente debera hacerlo
creando un nuevo tipo derivado del existente. Para obtener ms informacin, vea Herencia.
Al usar un mtodo de extensin para ampliar un tipo cuyo cdigo fuente no se puede cambiar, se corre el riesgo
de que un cambio en la implementacin del tipo interrumpa el mtodo de extensin.
Si se implementan mtodos de extensin para un tipo determinado, recuerde los puntos siguientes:
Nunca se llamar a un mtodo de extensin si tiene la misma signatura que un mtodo definido en el tipo.
Los mtodos de extensin se incluyen en el mbito en el nivel de espacio de nombres. Por ejemplo, si se
tienen varias clases estticas que contienen mtodos de extensin en un nico espacio de nombres
denominado Extensions , la directiva using Extensions; los incluir a todos en el mbito.

Para una biblioteca de clases ya implementada, no deben usarse mtodos de extensin para evitar incrementar el
nmero de versin de un ensamblado. Si desea agregar una funcionalidad significativa a una biblioteca de la que
es propietario del cdigo fuente, deben seguirse las instrucciones de .NET Framework estndar para el control de
versiones de ensamblado. Para obtener ms informacin, vea Versiones de los ensamblados.

Vea tambin
Gua de programacin de C#
Ejemplos de programacin en paralelo (incluyen numerosos mtodos de extensin de ejemplo)
Expresiones lambda
Informacin general sobre operadores de consulta estndar
Conversion rules for Instance parameters and their impact (Reglas de conversin para los parmetros de instancia
y su impacto)
Extension methods Interoperability between languages (Interoperabilidad de los mtodos de extensin entre
lenguajes)
Extension methods and Curried Delegates (Mtodos de extensin y delegados currificados)
Extension method Binding and Error reporting (Enlazar mtodos de extensin y notificacin de errores)
Cmo: Implementar e invocar un mtodo de
extensin personalizado (Gua de programacin de
C#)
03/10/2017 2 min to read Edit Online

En este tema se muestra cmo implementar sus propios mtodos de extensin para cualquier tipo de la biblioteca
de clases .NET Framework o para cualquier otro tipo .NET que desee extender. El cdigo de cliente puede usar los
mtodos de extensin agregando una referencia a la DLL que los contiene y agregando una directiva using que
especifique el espacio de nombres en el que se definen los mtodos de extensin.

Para definir y llamar al mtodo de extensin


1. Defina una class esttica que contenga el mtodo de extensin.
La clase debe estar visible para el cdigo de cliente. Para obtener ms informacin sobre las reglas de
accesibilidad, vea Modificadores de acceso.
2. Implemente el mtodo de extensin como un mtodo esttico con al menos la misma visibilidad que la clase
contenedora.
3. El primer parmetro del mtodo especifica el tipo en el que opera el mtodo; debe ir precedido del
modificador this.
4. En el cdigo de llamada, agregue una directiva using para especificar el espacio de nombres que contiene
la clase del mtodo de extensin.
5. Llame a los mtodos como si fueran mtodos de instancia del tipo.
Tenga en cuenta que el primer parmetro no se especifica mediante el cdigo de llamada, ya que representa
el tipo al que se aplica el operador y el compilador ya conoce el tipo del objeto. Solo tiene que proporcionar
argumentos para los parmetros comprendidos entre el 2 y n .

Ejemplo
En el ejemplo siguiente se implementa un mtodo de extensin denominado WordCount en la clase
CustomExtensions.StringExtension . El mtodo opera en la clase String, que se especifica como el primer parmetro
de mtodo. El espacio de nombres CustomExtensions se importa en el espacio de nombres de la aplicacin y se
llama al mtodo dentro del mtodo Main .
using System.Linq;
using System.Text;
using System;

namespace CustomExtensions
{
//Extension methods must be defined in a static class
public static class StringExtension
{
// This is the extension method.
// The first parameter takes the "this" modifier
// and specifies the type for which the method is defined.
public static int WordCount(this String str)
{
return str.Split(new char[] {' ', '.','?'}, StringSplitOptions.RemoveEmptyEntries).Length;
}
}
}
namespace Extension_Methods_Simple
{
//Import the extension method namespace.
using CustomExtensions;
class Program
{
static void Main(string[] args)
{
string s = "The quick brown fox jumped over the lazy dog.";
// Call the method as if it were an
// instance method on the type. Note that the first
// parameter is not specified by the calling code.
int i = s.WordCount();
System.Console.WriteLine("Word count of s is {0}", i);
}
}
}

Compilar el cdigo
Para ejecutar este cdigo, cpielo y pguelo en un proyecto de aplicacin de la consola de Visual C# creado en
Visual Studio. De forma predeterminada, este proyecto tiene como destino la versin 3.5 de .NET Framework y
tiene una referencia a System.Core.dll y una directiva using para System.Linq. Si faltan uno o varios de estos
requisitos del proyecto, se pueden agregar manualmente.

Seguridad de .NET Framework


Los mtodos de extensin no presentan ninguna vulnerabilidad de seguridad especfica. No se pueden usar nunca
para suplantar los mtodos existentes en un tipo, porque todos los conflictos de nombres se resuelven a favor de la
instancia o del mtodo esttico definido por el tipo en cuestin. Los mtodos de extensin no pueden tener acceso
a los datos privados de la clase extendida.

Vea tambin
Gua de programacin de C#
Mtodos de extensin
LINQ (Language-Integrated Query)
Clases estticas y sus miembros
protected
internal
public
this
namespace
Cmo: Crear un mtodo nuevo para una
enumeracin (Gua de programacin de C#)
03/10/2017 1 min to read Edit Online

Puede usar mtodos de extensin para agregar funcionalidad a un tipo de enumeracin concreto.

Ejemplo
En el ejemplo siguiente, la enumeracin Grades representa las posibles calificaciones con letras que un alumno
puede recibir en una clase. Un mtodo de extensin denominado Passing se agrega al tipo Grades para que cada
instancia de ese tipo "sepa" ahora si representa una calificacin de aprobado o no.

using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;

namespace EnumExtension
{
// Define an extension method in a non-nested static class.
public static class Extensions
{
public static Grades minPassing = Grades.D;
public static bool Passing(this Grades grade)
{
return grade >= minPassing;
}
}

public enum Grades { F = 0, D=1, C=2, B=3, A=4 };


class Program
{
static void Main(string[] args)
{
Grades g1 = Grades.D;
Grades g2 = Grades.F;
Console.WriteLine("First {0} a passing grade.", g1.Passing() ? "is" : "is not");
Console.WriteLine("Second {0} a passing grade.", g2.Passing() ? "is" : "is not");

Extensions.minPassing = Grades.C;
Console.WriteLine("\r\nRaising the bar!\r\n");
Console.WriteLine("First {0} a passing grade.", g1.Passing() ? "is" : "is not");
Console.WriteLine("Second {0} a passing grade.", g2.Passing() ? "is" : "is not");
}
}
}
/* Output:
First is a passing grade.
Second is not a passing grade.

Raising the bar!

First is not a passing grade.


Second is not a passing grade.
*/

Tenga en cuenta que la clase Extensions tambin contiene una variable esttica que se actualiza dinmicamente y
que el valor devuelto del mtodo de extensin refleja el valor actual de esa variable. Esto demuestra que, en
segundo plano, los mtodos de extensin se invocan directamente en la clase esttica en donde se definen.

Compilar el cdigo
Para ejecutar este cdigo, cpielo y pguelo en un proyecto de aplicacin de la consola de Visual C# creado en
Visual Studio. De forma predeterminada, este proyecto tiene como destino la versin 3.5 de .NET Framework y tiene
una referencia a System.Core.dll y una directiva using para System.Linq. Si faltan uno o varios de estos requisitos
del proyecto, se pueden agregar manualmente.

Vea tambin
Gua de programacin de C#
Mtodos de extensin
Argumentos opcionales y con nombre (Gua de
programacin de C#)
03/10/2017 8 min to read Edit Online

C# 4 introduce argumentos opcionales y con nombre. Los argumentos con nombre permiten especificar un
argumento para un parmetro concreto asociando el argumento al nombre del parmetro y no a la posicin del
parmetro en la lista de parmetros. Los argumentos opcionales permiten omitir argumentos para algunos
parmetros. Ambas tcnicas se pueden usar con mtodos, indexadores, constructores y delegados.
Cuando se usan argumentos opcionales y con nombre, los argumentos se evalan por el orden en que aparecen en
la lista de argumentos, no en la lista de parmetros.
Los parmetros opcionales y con nombre, cuando se usan conjuntamente, solo permiten especificar argumentos
para algunos parmetros de una lista de parmetros opcionales. Esta funcionalidad facilita enormemente las
llamadas a interfaces COM, como las API de automatizacin de Microsoft Office.

Argumentos con nombre


Los argumentos con nombre le liberan de la necesidad de recordar o buscar el orden de los parmetros de la lista
de parmetros de los mtodos llamados. El parmetro de cada argumento se puede especificar por nombre de
parmetro. Por ejemplo, una funcin que calcula el ndice de masa corporal (IMC) se puede llamar de manera
estndar enviando argumentos de peso y estatura por posicin en el orden que define la funcin.
CalculateBMI(123, 64);

Si no recuerda el orden de los parmetros pero conoce sus nombres, puede enviar los argumentos en cualquier
orden, primero el peso o primero la estatura.
CalculateBMI(weight: 123, height: 64);

CalculateBMI(height: 64, weight: 123);

Los argumentos con nombre tambin mejoran la legibilidad del cdigo al identificar lo que cada argumento
representa.
Un argumento con nombre puede seguir a los argumentos posicionales, tal y como se muestra aqu.
CalculateBMI(123, height: 64);

Pero un argumento posicional no puede seguir a un argumento con nombre. La instruccin siguiente genera un
error del compilador.
//CalculateBMI(weight: 123, 64);

Ejemplo
El cdigo siguiente implementa los ejemplos de esta seccin.
class NamedExample
{
static void Main(string[] args)
{
// The method can be called in the normal way, by using positional arguments.
PrintOrderDetails("Gift Shop", 31, "Red Mug");

// Named arguments can be supplied for the parameters in any order.


PrintOrderDetails(orderNum: 31, productName: "Red Mug", sellerName: "Gift Shop");
PrintOrderDetails(productName: "Red Mug", sellerName: "Gift Shop", orderNum: 31);

// Named arguments mixed with positional arguments are valid


// as long as they are used in their correct position.
PrintOrderDetails("Gift Shop", 31, productName: "Red Mug");
PrintOrderDetails(sellerName: "Gift Shop", 31, productName: "Red Mug"); // C# 7.2 onwards
PrintOrderDetails("Gift Shop", orderNum: 31, "Red Mug"); // C# 7.2 onwards

// However, mixed arguments are invalid if used out-of-order.


// The following statements will cause a compiler error.
// PrintOrderDetails(productName: "Red Mug", 31, "Gift Shop");
// PrintOrderDetails(31, sellerName: "Gift Shop", "Red Mug");
// PrintOrderDetails(31, "Red Mug", sellerName: "Gift Shop");
}

static void PrintOrderDetails(string sellerName, int orderNum, string productName)


{
if (string.IsNullOrWhiteSpace(sellerName))
{
throw new ArgumentException(message: "Seller name cannot be null or empty.", paramName:
nameof(sellerName));
}

Console.WriteLine($"Seller: {sellerName}, Order #: {orderNum}, Product: {productName}");


}
}

Argumentos opcionales
La definicin de un mtodo, constructor, indexador o delegado puede especificar que sus parmetros son
necesarios o que son opcionales. Todas las llamadas deben proporcionar argumentos para todos los parmetros
necesarios, pero pueden omitir los argumentos para los parmetros opcionales.
Cada parmetro opcional tiene un valor predeterminado como parte de su definicin. Si no se enva ningn
argumento para ese parmetro, se usa el valor predeterminado. Un valor predeterminado debe ser uno de los
siguientes tipos de expresiones:
una expresin constante;
una expresin con el formato new ValType() , donde ValType es un tipo de valor, como enum o struct;
una expresin con el formato default(ValType), donde ValType es un tipo de valor.
Los parmetros opcionales se definen al final de la lista de parmetros despus de los parmetros necesarios. Si el
autor de la llamada proporciona un argumento para algn parmetro de una sucesin de parmetros opcionales,
debe proporcionar argumentos para todos los parmetros opcionales anteriores. No se admiten espacios
separados por comas en la lista de argumentos. Por ejemplo, en el cdigo siguiente, el mtodo de instancia
ExampleMethod se define con un parmetro necesario y dos opcionales.

public void ExampleMethod(int required, string optionalstr = "default string",


int optionalint = 10)
La llamada siguiente a ExampleMethod genera un error del compilador, porque se proporciona un argumento para
el tercer parmetro pero no para el segundo.
//anExample.ExampleMethod(3, ,4);

Pero si conoce el nombre del tercer parmetro, puede usar un argumento con nombre para realizar la tarea.
anExample.ExampleMethod(3, optionalint: 4);

IntelliSense usa corchetes para indicar parmetros opcionales, tal y como se muestra en la ilustracin siguiente.

Parmetros opcionales en ExampleMethod

NOTA
Tambin puede declarar parmetros opcionales con la clase OptionalAttribute de .NET. Los parmetros OptionalAttribute
no requieren un valor predeterminado.

Ejemplo
En el ejemplo siguiente, el constructor de ExampleClass tiene un solo parmetro, que es opcional. El mtodo de
instancia ExampleMethod tiene un parmetro necesario, required , y dos parmetros opcionales, optionalstr y
optionalint . El cdigo de Main muestra las distintas formas en que se pueden invocar el constructor y el mtodo.

namespace OptionalNamespace
{
class OptionalExample
{
static void Main(string[] args)
{
// Instance anExample does not send an argument for the constructor's
// optional parameter.
ExampleClass anExample = new ExampleClass();
anExample.ExampleMethod(1, "One", 1);
anExample.ExampleMethod(2, "Two");
anExample.ExampleMethod(3);

// Instance anotherExample sends an argument for the constructor's


// optional parameter.
ExampleClass anotherExample = new ExampleClass("Provided name");
anotherExample.ExampleMethod(1, "One", 1);
anotherExample.ExampleMethod(2, "Two");
anotherExample.ExampleMethod(3);

// The following statements produce compiler errors.

// An argument must be supplied for the first parameter, and it


// must be an integer.
//anExample.ExampleMethod("One", 1);
//anExample.ExampleMethod();

// You cannot leave a gap in the provided arguments.


//anExample.ExampleMethod(3, ,4);
//anExample.ExampleMethod(3, 4);

// You can use a named parameter to make the previous


// statement work.
anExample.ExampleMethod(3, optionalint: 4);
}
}
}

class ExampleClass
{
private string _name;

// Because the parameter for the constructor, name, has a default


// value assigned to it, it is optional.
public ExampleClass(string name = "Default name")
{
_name = name;
}

// The first parameter, required, has no default value assigned


// to it. Therefore, it is not optional. Both optionalstr and
// optionalint have default values assigned to them. They are optional.
public void ExampleMethod(int required, string optionalstr = "default string",
int optionalint = 10)
{
Console.WriteLine("{0}: {1}, {2}, and {3}.", _name, required, optionalstr,
optionalint);
}
}

// The output from this example is the following:


// Default name: 1, One, and 1.
// Default name: 2, Two, and 10.
// Default name: 3, default string, and 10.
// Provided name: 1, One, and 1.
// Provided name: 2, Two, and 10.
// Provided name: 3, default string, and 10.
// Default name: 3, default string, and 4.

Interfaces COM
Los argumentos opcionales y con nombre, adems de compatibilidad con objetos dinmicos y otros avances,
mejoran considerablemente la interoperabilidad con las API de COM, como las API de automatizacin de Office.
Por ejemplo, el mtodo AutoFormat de la interfaz Range de Microsoft Office Excel tiene siete parmetros, todos
ellos opcionales. Estos parmetros se muestran en la siguiente ilustracin.

Parmetros de AutoFormat
En C# 3.0 y versiones anteriores, se requiere un argumento para cada parmetro, tal y como se muestra en el
ejemplo siguiente.
// In C# 3.0 and earlier versions, you need to supply an argument for
// every parameter. The following call specifies a value for the first
// parameter, and sends a placeholder value for the other six. The
// default values are used for those parameters.
var excelApp = new Microsoft.Office.Interop.Excel.Application();
excelApp.Workbooks.Add();
excelApp.Visible = true;

var myFormat =
Microsoft.Office.Interop.Excel.XlRangeAutoFormat.xlRangeAutoFormatAccounting1;

excelApp.get_Range("A1", "B4").AutoFormat(myFormat, Type.Missing,


Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);

Pero la llamada a AutoFormat se puede simplificar considerablemente mediante argumentos opcionales y con
nombre, que se introducen en C# 4.0. Los parmetros opcionales y con nombre permiten omitir el argumento de
un parmetro opcional si no se quiere cambiar el valor predeterminado del parmetro. En la siguiente llamada,
solo se especifica un valor para uno de los siete parmetros.

// The following code shows the same call to AutoFormat in C# 4.0. Only
// the argument for which you want to provide a specific value is listed.
excelApp.Range["A1", "B4"].AutoFormat( Format: myFormat );

Para obtener ms informacin y ejemplos, vea How to: Use Named and Optional Arguments in Office
Programming [Cmo: Usar argumentos opcionales y con nombre en la programacin de Office (Gua de
programacin de C#)] y How to: Access Office Interop Objects by Using Visual C# Features [Cmo: Tener acceso a
objetos de interoperabilidad de Office mediante las caractersticas de Visual C# (Gua de programacin de C#)].

Overload Resolution
El uso de argumentos opcionales y con nombre afecta a la resolucin de sobrecarga de las maneras siguientes:
Un mtodo, indexador o constructor es un candidato para la ejecucin si cada uno de sus parmetros es
opcional o corresponde, por nombre o por posicin, a un solo argumento de la instruccin de llamada y el
argumento se puede convertir al tipo del parmetro.
Si se encuentra ms de un candidato, se aplican las reglas de resolucin de sobrecarga de las conversiones
preferidas a los argumentos que se especifican explcitamente. Los argumentos omitidos en parmetros
opcionales se ignoran.
Si dos candidatos se consideran igualmente correctos, la preferencia pasa a un candidato que no tenga
parmetros opcionales cuyos argumentos se hayan omitido en la llamada. Se trata de una consecuencia de
una preferencia general en la resolucin de sobrecarga para los candidatos con menos parmetros.

Especificacin del lenguaje C#


Para obtener ms informacin, consulte la Especificacin del lenguaje C#. La especificacin del lenguaje es la fuente
definitiva de la sintaxis y el uso de C#.

Vea tambin
How to: Use Named and Optional Arguments in Office Programming [Cmo: Usar argumentos opcionales y con
nombre en la programacin de Office (Gua de programacin de C#)]
Uso de tipo dinmico
Using Constructors [Uso de constructores (Gua de programacin de C#)]
Utilizar indizadores
Cmo: Usar argumentos opcionales y con nombre en
la programacin de Office (Gua de programacin de
C#)
03/10/2017 5 min to read Edit Online

Los argumentos con nombre y los argumentos opcionales, introducidos en C# 4, mejoran la comodidad, la
flexibilidad y la legibilidad en la programacin de C#. Adems, estas caractersticas facilitan enormemente el acceso
a interfaces COM, como las API de automatizacin de Microsoft Office.
En el ejemplo siguiente, el mtodo ConvertToTable tiene diecisis parmetros que representan las caractersticas
de una tabla, como el nmero de columnas y filas, el formato, los bordes, las fuentes y los colores. Los diecisis
parmetros son opcionales, ya que la mayora de las veces no interesa especificar valores concretos para todos
ellos. Pero si no hay argumentos opcionales y con nombre, es necesario proporcionar un valor o un valor de
marcador de posicin para cada parmetro. Con los argumentos opcionales y con nombre, puede especificar
valores solamente para los parmetros necesarios para el proyecto.
Debe tener Microsoft Office Word instalado en el equipo para completar estos procedimientos.

NOTA
Es posible que tu equipo muestre nombres o ubicaciones diferentes para algunos de los elementos de la interfaz de usuario
de Visual Studio en las siguientes instrucciones. La edicin de Visual Studio que se tenga y la configuracin que se utilice
determinan estos elementos. Para obtener ms informacin, vea Personalizar el IDE.

Para crear una aplicacin de consola nueva


1. Inicie Visual Studio.
2. En el men Archivo , elija Nuevoy haga clic en Proyecto.
3. En el panel Templates Categories (Categoras de plantillas), expanda Visual C# y haga clic en Windows.
4. En la parte superior del panel Plantillas, asegrese de que .NET Framework 4 aparece en el cuadro
Plataforma de destino.
5. En el panel Plantillas, haga clic en Aplicacin de consola.
6. Escriba un nombre para el proyecto en el campo Nombre.
7. Haga clic en Aceptar.
El proyecto nuevo aparece en el Explorador de soluciones.
Para agregar una referencia
1. En el Explorador de soluciones, haga clic con el botn derecho en el nombre del proyecto y seleccione
Agregar referencia. Aparecer el cuadro de dilogo Agregar referencia.
2. En la pgina .NET, seleccione Microsoft.Office.Interop.Word en la lista Nombre de componente.
3. Haga clic en Aceptar.
Para agregar las directivas using necesarias
1. En el Explorador de soluciones, haga clic con el botn derecho en el archivo Program.cs y, despus, haga
clic en Ver cdigo.
2. Agregue las directivas using siguientes a la parte superior del archivo de cdigo.

using Word = Microsoft.Office.Interop.Word;

Para mostrar texto en un documento de Word


1. En la clase Program en Program.cs, agregue el mtodo siguiente para crear una aplicacin de Word y un
documento de Word. El mtodo Add tiene cuatro parmetros opcionales. En este ejemplo se usan los
valores predeterminados. Por lo tanto, no se necesitan argumentos en la instruccin de llamada.

static void DisplayInWord()


{
var wordApp = new Word.Application();
wordApp.Visible = true;
// docs is a collection of all the Document objects currently
// open in Word.
Word.Documents docs = wordApp.Documents;

// Add a document to the collection and name it doc.


Word.Document doc = docs.Add();
}

2. Agregue el cdigo siguiente al final del mtodo para definir dnde se muestra texto en el documento y qu
texto se muestra.

// Define a range, a contiguous area in the document, by specifying


// a starting and ending character position. Currently, the document
// is empty.
Word.Range range = doc.Range(0, 0);

// Use the InsertAfter method to insert a string at the end of the


// current range.
range.InsertAfter("Testing, testing, testing. . .");

Para ejecutar la aplicacin


1. Agregue la instruccin siguiente a Main.

DisplayInWord();

2. Presione CTRL+F5 para ejecutar el proyecto. Aparecer un documento de Word con el texto especificado.
Para convertir el texto en tabla
1. Use el mtodo ConvertToTable para incluir el texto en una tabla. El mtodo tiene 16 parmetros opcionales.
IntelliSense coloca los parmetros opcionales entre corchetes, tal como se muestra en la ilustracin
siguiente.

Parmetros de ConvertToTable
Los argumentos opcionales y con nombre permiten especificar valores solo para los parmetros que quiere
cambiar. Agregue el cdigo siguiente al final del mtodo DisplayInWord para crear una tabla simple. El
argumento especifica que las comas de la cadena de texto de range separan las celdas de la tabla.

// Convert to a simple table. The table will have a single row with
// three columns.
range.ConvertToTable(Separator: ",");

En versiones anteriores de C#, la llamada a ConvertToTable requiere un argumento de referencia para cada
parmetro, tal como se muestra en el cdigo siguiente.

// Call to ConvertToTable in Visual C# 2008 or earlier. This code


// is not part of the solution.
var missing = Type.Missing;
object separator = ",";
range.ConvertToTable(ref separator, ref missing, ref missing,
ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing, ref missing,
ref missing);

2. Presione CTRL+F5 para ejecutar el proyecto.


Para experimentar con otros parmetros
1. Para cambiar la tabla de modo que tenga una columna y tres filas, reemplace la ltima lnea de
DisplayInWord por la instruccin siguiente y escriba CTRL+F5.

range.ConvertToTable(Separator: ",", AutoFit: true, NumColumns: 1);

2. Para especificar un formato predefinido para la tabla, reemplace la ltima lnea de DisplayInWord por la
instruccin siguiente y escriba CTRL+F5. El formato puede ser cualquiera de las constantes WdTableFormat.

range.ConvertToTable(Separator: ",", AutoFit: true, NumColumns: 1,


Format: Word.WdTableFormat.wdTableFormatElegant);

Ejemplo
En el cdigo siguiente se incluye el ejemplo completo.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Word = Microsoft.Office.Interop.Word;

namespace OfficeHowTo
{
class WordProgram
{
static void Main(string[] args)
{
DisplayInWord();
}

static void DisplayInWord()


{
var wordApp = new Word.Application();
wordApp.Visible = true;
// docs is a collection of all the Document objects currently
// open in Word.
Word.Documents docs = wordApp.Documents;

// Add a document to the collection and name it doc.


Word.Document doc = docs.Add();

// Define a range, a contiguous area in the document, by specifying


// a starting and ending character position. Currently, the document
// is empty.
Word.Range range = doc.Range(0, 0);

// Use the InsertAfter method to insert a string at the end of the


// current range.
range.InsertAfter("Testing, testing, testing. . .");

// You can comment out any or all of the following statements to


// see the effect of each one in the Word document.

// Next, use the ConvertToTable method to put the text into a table.
// The method has 16 optional parameters. You only have to specify
// values for those you want to change.

// Convert to a simple table. The table will have a single row with
// three columns.
range.ConvertToTable(Separator: ",");

// Change to a single column with three rows..


range.ConvertToTable(Separator: ",", AutoFit: true, NumColumns: 1);

// Format the table.


range.ConvertToTable(Separator: ",", AutoFit: true, NumColumns: 1,
Format: Word.WdTableFormat.wdTableFormatElegant);
}
}
}

Vea tambin
Argumentos opcionales y con nombre
Constructores (Gua de programacin de C#)
03/10/2017 2 min to read Edit Online

Cada vez que se crea una clase o struct, se llama a su constructor. Una clase o struct puede tener varios
constructores que toman argumentos diferentes. Los constructores permiten al programador establecer valores
predeterminados, limitar la creacin de instancias y escribir cdigo flexible y fcil de leer. Para obtener ms
informacin y ejemplos, vea Usar constructores y Constructores de instancias.

Constructores predeterminados
Si no proporciona un constructor para la clase, C# crear uno de manera predeterminada que cree instancias del
objeto y establezca las variables miembro en los valores predeterminados que se indican en Tabla de valores
predeterminados. Si no proporciona un constructor para su struct, C# se basa en un constructor predeterminado
implcito para inicializar automticamente cada campo de un tipo de valor en su valor predeterminado como se
muestra en la Tabla de valores predeterminados. Para obtener ms informacin y ejemplos, vea Constructores
de instancias.

Sintaxis del constructor


Un constructor es un mtodo cuyo nombre es igual que el nombre de su tipo. Su firma del mtodo incluye solo
el nombre del mtodo y su lista de parmetros; no incluye un tipo de valor devuelto. En el ejemplo siguiente se
muestra el constructor de una clase denominada Person .

public class Person


{
private string last;
private string first;

public Person(string lastName, string firstName)


{
last = lastName;
first = firstName;
}

// Remaining implementation of Person class.


}

Si un constructor puede implementarse como una instruccin nica, puede usar una definicin del cuerpo de
expresin. En el ejemplo siguiente se define una clase Location cuyo constructor tiene un nico parmetro de
cadena denominado name. La definicin del cuerpo de expresin asigna el argumento al campo locationName .

public class Location


{
private string locationName;

public Location(string name) => locationName = name;

public string Name


{
get => locationName;
set => locationName = value;
}
}
Constructores estticos
En los ejemplos anteriores se han mostrado constructores de instancia, que crean un objeto nuevo. Una clase o
struct tambin puede tener un constructor esttico, que inicializa los miembros estticos del tipo. Los
constructores estticos no tienen parmetros. Si no proporciona un constructor esttico para inicializar los
campos estticos, el compilador de C# proporcionar un constructor esttico predeterminado que inicializa los
campos estticos en su valor predeterminado como se muestra en la Tabla de valores predeterminados.
En el ejemplo siguiente se usa un constructor esttico para inicializar un campo esttico.

public class Adult : Person


{
private static int minimumAge;

public Adult(string lastName, string firstName) : base(lastName, firstName)


{ }

static Adult()
{
minimumAge = 18;
}

// Remaining implementation of Adult class.


}

Tambin puede definir un constructor esttico con una definicin de cuerpo de expresin, como se muestra en el
ejemplo siguiente.

public class Child : Person


{
private static int maximumAge;

public Child(string lastName, string firstName) : base(lastName, firstName)


{ }

static Child() => maximumAge = 18;

// Remaining implementation of Child class.


}

Para obtener ms informacin y ejemplos, vea Constructores estticos.

En esta seccin
Utilizar constructores
Constructores de instancias
Constructores privados
Constructores estticos
Cmo: Escribir un constructor Copy

Vea tambin
Gua de programacin de C#
Clases y estructuras
Finalizadores
static
Why Do Initializers Run In The Opposite Order As Constructors? Part One (Por qu los inicializadores se
ejecutan en orden contrario a los constructores? Parte uno)
Utilizar constructores (Gua de programacin de C#)
03/10/2017 4 min to read Edit Online

Cuando se crea una class o un struct, se llama a su constructor. Los constructores tienen el mismo nombre que la
class o el struct y suelen inicializar los miembros de datos del nuevo objeto.
En el ejemplo siguiente, una clase denominada Taxi se define mediante un constructor simple. Luego, se crea
una instancia de la clase con el operador new. El constructor Taxi se invoca con el operador new
inmediatamente despus de asignar memoria para el nuevo objeto.

public class Taxi


{
public bool isInitialized;
public Taxi()
{
isInitialized = true;
}
}

class TestTaxi
{
static void Main()
{
Taxi t = new Taxi();
Console.WriteLine(t.isInitialized);
}
}

Un constructor que no toma ningn parmetro se denomina constructor predeterminado. Los constructores
predeterminados se invocan cada vez que se crea una instancia de un objeto mediante el operador new y no se
especifica ningn argumento en new . Para obtener ms informacin, vea Instance Constructors (Constructores de
instancias [Gua de programacin de C#]).
A menos que la clase sea static, las clases sin constructores tienen un constructor pblico predeterminado por el
compilador de C# con el fin de habilitar la creacin de instancias de clase. Para obtener ms informacin, consulte
Clases estticas y sus miembros.
Puede impedir que se cree una instancia de una clase convirtiendo el constructor en privado, de la manera
siguiente:

class NLog
{
// Private Constructor:
private NLog() { }

public static double e = Math.E; //2.71828...


}

Para obtener ms informacin, vea Private Constructors (Constructores privados [Gua de programacin de C#]).
Los constructores de tipos struct son similares a los constructores de clases, pero structs no puede contener un
constructor predeterminado explcito porque el compilador proporciona uno automticamente. Este constructor
inicializa cada campo del struct en los valores predeterminados. Para obtener ms informacin, vea Default
Values Table (Tabla de valores predeterminados [Referencia de C#]). Pero este constructor predeterminado solo
se invoca si las instancias de struct se crean con new . Por ejemplo, este cdigo usa el constructor
predeterminado para Int32, por lo que se tiene la certeza de que el entero se inicializa:

int i = new int();


Console.WriteLine(i);

Si bien, el siguiente cdigo genera un error del compilador porque no usa new y porque intenta usar un objeto
que no se ha inicializado:

int i;
Console.WriteLine(i);

Tambin puede inicializar o asignar los objetos basados en structs (incluidos todos los tipos numricos
integrados) y luego usarlos como en el ejemplo siguiente:

int a = 44; // Initialize the value type...


int b;
b = 33; // Or assign it before using it.
Console.WriteLine("{0}, {1}", a, b);

Por lo que no es necesario llamar al constructor predeterminado para un tipo de valor.


Tanto las clases como los structs pueden definir constructores que toman parmetros. Los constructores que
toman parmetros deben llamarse mediante una instruccin new o base. Las clases y structs tambin pueden
definir varios constructores y no es necesario definir un constructor predeterminado. Por ejemplo:

public class Employee


{
public int salary;

public Employee(int annualSalary)


{
salary = annualSalary;
}

public Employee(int weeklySalary, int numberOfWeeks)


{
salary = weeklySalary * numberOfWeeks;
}
}

Esta clase se puede crear mediante cualquiera de las siguientes instrucciones:

Employee e1 = new Employee(30000);


Employee e2 = new Employee(500, 52);

Un constructor puede usar la palabra clave base para llamar al constructor de una clase base. Por ejemplo:
public class Manager : Employee
{
public Manager(int annualSalary)
: base(annualSalary)
{
//Add further instructions here.
}
}

En este ejemplo, se llama al constructor de la clase base antes de ejecutar el bloque del constructor. La palabra
clave base puede usarse con o sin parmetros. Los parmetros del constructor se pueden usar como parmetros
en base o como parte de una expresin. Para obtener ms informacin, vea base.
En una clase derivada, si un constructor de clase base no se llama explcitamente con la palabra clave base , se
llama implcitamente al constructor predeterminado, si hay alguno. Esto significa que las siguientes declaraciones
del constructor son en efecto iguales:

public Manager(int initialdata)


{
//Add further instructions here.
}

public Manager(int initialdata)


: base()
{
//Add further instructions here.
}

Si una clase base no proporciona un constructor predeterminado, la clase derivada debe realizar una llamada
explcita a un constructor base mediante base .
Un constructor puede invocar otro constructor en el mismo objeto mediante la palabra clave this. Igual que base ,
this puede usarse con o sin parmetros. Adems, los parmetros del constructor estn disponibles como
parmetros en this o como parte de una expresin. Por ejemplo, el segundo constructor del ejemplo anterior se
puede reescribir con this :

public Employee(int weeklySalary, int numberOfWeeks)


: this(weeklySalary * numberOfWeeks)
{
}

El uso de la palabra clave this en el ejemplo anterior llama a este constructor:

public Employee(int annualSalary)


{
salary = annualSalary;
}

Los constructores se pueden marcar como public, private, protected, internal o protected internal . Estos
modificadores de acceso definen cmo los usuarios de la clase pueden construir la clase. Para obtener ms
informacin, consulte Modificadores de acceso.
Un constructor puede declararse esttico mediante la palabra clave static. Los constructores estticos se llaman
automticamente, inmediatamente antes de acceder a los campos estticos y, por lo general, se usan para
inicializar miembros de clase esttica. Para obtener ms informacin, vea Static Constructors (Constructores
estticos [Gua de programacin de C#]).

Especificacin del lenguaje C#


Para obtener ms informacin, consulte la Especificacin del lenguaje C#. La especificacin del lenguaje es la
fuente definitiva de la sintaxis y el uso de C#.

Vea tambin
Gua de programacin de C#
Clases y estructuras
Constructors (Constructores [Gua de programacin de C#])
Finalizadores
Constructores de instancias (Gua de programacin
de C#)
03/10/2017 4 min to read Edit Online

Los constructores de instancias se usan para crear e inicializar las variables miembro de instancia cuando se usa
la expresin new para crear un objeto de una clase. Para inicializar una clase esttica, o variables estticas en una
clase no esttica, se debe definir un constructor esttico. Para obtener ms informacin, vea Static Constructors
(Constructores estticos [Gua de programacin de C#]).
En el siguiente ejemplo se muestra un constructor de instancias:

class CoOrds
{
public int x, y;

// constructor
public CoOrds()
{
x = 0;
y = 0;
}
}

NOTA
Para mayor claridad, esta clase contiene campos pblicos. El uso de campos pblicos no es una prctica de programacin
recomendada porque permite que cualquier mtodo de cualquier parte de un programa obtenga acceso sin restricciones ni
comprobaciones a los mecanismos internos de un objeto. Los miembros de datos generalmente deberan ser privados y
solo se debera tener acceso a ellos a travs de las propiedades y mtodos de la clase.

Se llama a este constructor de instancias cada vez que se crea un objeto basado en la clase CoOrds . Un
constructor como este, que no toma ningn argumento, se denomina constructor predeterminado. Pero a
menudo resulta til proporcionar constructores adicionales. Por ejemplo, se puede agregar un constructor a la
clase CoOrds que permita especificar los valores iniciales de los miembros de datos:

// A constructor with two arguments:


public CoOrds(int x, int y)
{
this.x = x;
this.y = y;
}

Esto permite crear objetos CoOrd con valores iniciales predeterminados o especficos, como este:

CoOrds p1 = new CoOrds();


CoOrds p2 = new CoOrds(5, 3);

Si una clase no tiene un constructor, se genera automticamente un constructor predeterminado y los valores
predeterminados se usan para inicializar los campos del objeto. Por ejemplo, un int se inicializa en 0. Para ms
informacin sobre los valores predeterminados, vea Tabla de valores predeterminados (Referencia de C#). Por
tanto, dado que el constructor predeterminado de la clase CoOrds inicializa todos los miembros de datos en cero,
se puede quitar por completo sin cambiar el funcionamiento de la clase. Ms adelante en este tema se
proporciona un ejemplo completo del uso de varios constructores en el Ejemplo 1 y en el Ejemplo 2 se
proporciona un ejemplo de un constructor generado automticamente.
Los constructores de instancias tambin se pueden usar para llamar a los constructores de instancias de las clases
base. El constructor de clase puede invocar el constructor de la clase base a travs del inicializador, como sigue:

class Circle : Shape


{
public Circle(double radius)
: base(radius, 0)
{
}
}

En este ejemplo, la clase Circle pasa valores que representan el radio y el alto al constructor proporcionado por
Shape desde el que se deriva Circle . Un ejemplo completo del uso de Shape y Circle aparece en este tema en
el Ejemplo 3.

Ejemplo 1
En el ejemplo siguiente se muestra una clase con dos constructores de clase, uno sin argumentos y uno con dos
argumentos.
class CoOrds
{
public int x, y;

// Default constructor:
public CoOrds()
{
x = 0;
y = 0;
}

// A constructor with two arguments:


public CoOrds(int x, int y)
{
this.x = x;
this.y = y;
}

// Override the ToString method:


public override string ToString()
{
return (String.Format("({0},{1})", x, y));
}
}

class MainClass
{
static void Main()
{
CoOrds p1 = new CoOrds();
CoOrds p2 = new CoOrds(5, 3);

// Display the results using the overriden ToString method:


Console.WriteLine("CoOrds #1 at {0}", p1);
Console.WriteLine("CoOrds #2 at {0}", p2);
Console.ReadKey();
}
}
/* Output:
CoOrds #1 at (0,0)
CoOrds #2 at (5,3)
*/

Ejemplo 2
En este ejemplo, la clase Person no tiene ningn constructor, en cuyo caso, se proporciona automticamente un
constructor predeterminado y los campos se inicializan en sus valores predeterminados.
public class Person
{
public int age;
public string name;
}

class TestPerson
{
static void Main()
{
Person person = new Person();

Console.WriteLine("Name: {0}, Age: {1}", person.name, person.age);


// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
// Output: Name: , Age: 0

Observe que el valor predeterminado de age es 0 y el valor predeterminado de name es null . Para ms
informacin sobre los valores predeterminados, vea Tabla de valores predeterminados (Referencia de C#).

Ejemplo 3
En el ejemplo siguiente se muestra cmo usar el inicializador de la clase base. La clase Circle se deriva de la
clase general Shape y la clase Cylinder se deriva de la clase Circle . En cada clase derivada, el constructor usa
su inicializador de clase base.
abstract class Shape
{
public const double pi = Math.PI;
protected double x, y;

public Shape(double x, double y)


{
this.x = x;
this.y = y;
}

public abstract double Area();


}

class Circle : Shape


{
public Circle(double radius)
: base(radius, 0)
{
}
public override double Area()
{
return pi * x * x;
}
}

class Cylinder : Circle


{
public Cylinder(double radius, double height)
: base(radius)
{
y = height;
}

public override double Area()


{
return (2 * base.Area()) + (2 * pi * x * y);
}
}

class TestShapes
{
static void Main()
{
double radius = 2.5;
double height = 3.0;

Circle ring = new Circle(radius);


Cylinder tube = new Cylinder(radius, height);

Console.WriteLine("Area of the circle = {0:F2}", ring.Area());


Console.WriteLine("Area of the cylinder = {0:F2}", tube.Area());

// Keep the console window open in debug mode.


Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
/* Output:
Area of the circle = 19.63
Area of the cylinder = 86.39
*/

Para obtener ms ejemplos sobre cmo invocar los constructores de clase base, vea virtual, override y base.
Vea tambin
Gua de programacin de C#
Clases y estructuras
Constructors (Constructores [Gua de programacin de C#])
Finalizadores
static
Constructores privados (Gua de programacin de
C#)
03/10/2017 1 min to read Edit Online

Un constructor privado es un constructor de instancia especial. Se usa generalmente en clases que contienen solo
miembros estticos. Si una clase tiene uno o ms constructores privados y ningn constructor pblico, el resto de
clases (excepto las anidadas) no podrn crear instancias de esta clase. Por ejemplo:

class NLog
{
// Private Constructor:
private NLog() { }

public static double e = Math.E; //2.71828...


}

La declaracin de un constructor vaco evita la generacin automtica de un constructor predeterminado. Observe


que si no usa un modificador de acceso en el constructor, este ser privado de manera predeterminada. En cambio,
normalmente se usa el modificador private de manera explcita para aclarar que no es posible crear una instancia
de la clase.
Los constructores privados se usan para evitar la creacin de instancias de una clase cuando no hay campos o
mtodos de instancia, por ejemplo, la clase Math, o cuando se llama a un mtodo para obtener una instancia de
una clase. Si todos los mtodos de la clase son estticos, considere convertir la clase completa en esttica. Para
obtener ms informacin, vea Clases estticas y sus miembros.

Ejemplo
El siguiente es un ejemplo de clase que usa un constructor privado.
public class Counter
{
private Counter() { }
public static int currentCount;
public static int IncrementCount()
{
return ++currentCount;
}
}

class TestCounter
{
static void Main()
{
// If you uncomment the following statement, it will generate
// an error because the constructor is inaccessible:
// Counter aCounter = new Counter(); // Error

Counter.currentCount = 100;
Counter.IncrementCount();
Console.WriteLine("New count: {0}", Counter.currentCount);

// Keep the console window open in debug mode.


Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
// Output: New count: 101

Observe que si quita el comentario de la siguiente instruccin del ejemplo, se producir un error porque el
constructor es inaccesible debido a su nivel de proteccin:

// Counter aCounter = new Counter(); // Error

Especificacin del lenguaje C#


Para obtener ms informacin, consulte la Especificacin del lenguaje C#. La especificacin del lenguaje es la
fuente definitiva de la sintaxis y el uso de C#.

Vea tambin
Gua de programacin de C#
Clases y estructuras
Constructors (Constructores [Gua de programacin de C#])
Finalizadores
private
public
Constructores estticos (Gua de programacin de
C#)
03/10/2017 3 min to read Edit Online

Un constructor esttico se usa para inicializar cualquier dato esttico o realizar una accin determinada que solo
debe realizarse una vez. Es llamado automticamente antes de crear la primera instancia o de hacer referencia a
cualquier miembro esttico.

class SimpleClass
{
// Static variable that must be initialized at run time.
static readonly long baseline;

// Static constructor is called at most one time, before any


// instance constructor is invoked or member is accessed.
static SimpleClass()
{
baseline = DateTime.Now.Ticks;
}
}

Los constructores estticos tienen las propiedades siguientes:


Un constructor esttico no permite modificadores de acceso ni tiene parmetros.
Se le llama automticamente para inicializar la clase antes de crear la primera instancia o de hacer
referencia a cualquier miembro esttico.
Un constructor esttico no puede ser llamado directamente.
El usuario no puede controlar cundo se ejecuta el constructor esttico en el programa.
Los constructores estticos se usan normalmente cuando la clase hace uso de un archivo de registro y el
constructor escribe entradas en dicho archivo.
Los constructores estticos tambin son tiles al crear clases contenedoras para cdigo no administrado,
cuando el constructor puede llamar al mtodo LoadLibrary .
Si un constructor esttico inicia una excepcin, el motor en tiempo de ejecucin no lo invocar una
segunda vez y el tipo seguir sin inicializar durante el perodo de duracin del dominio de aplicacin
donde se ejecuta el programa.

Ejemplo
En este ejemplo, la clase Bus tiene un constructor esttico. Cuando se crea la primera instancia de Bus ( bus1 ),
se invoca el constructor esttico para inicializar la clase. En el resultado del ejemplo, se comprueba que el
constructor esttico se ejecuta solo una vez, incluso si se crean dos instancias de Bus , y que se ejecuta antes de
que se ejecute el constructor de instancia.

public class Bus


{
// Static variable used by all Bus instances.
// Represents the time the first bus of the day starts its route.
protected static readonly DateTime globalStartTime;
// Property for the number of each bus.
protected int RouteNumber { get; set; }

// Static constructor to initialize the static variable.


// It is invoked before the first instance constructor is run.
static Bus()
{
globalStartTime = DateTime.Now;

// The following statement produces the first line of output,


// and the line occurs only once.
Console.WriteLine("Static constructor sets global start time to {0}",
globalStartTime.ToLongTimeString());
}

// Instance constructor.
public Bus(int routeNum)
{
RouteNumber = routeNum;
Console.WriteLine("Bus #{0} is created.", RouteNumber);
}

// Instance method.
public void Drive()
{
TimeSpan elapsedTime = DateTime.Now - globalStartTime;

// For demonstration purposes we treat milliseconds as minutes to simulate


// actual bus times. Do not do this in your actual bus schedule program!
Console.WriteLine("{0} is starting its route {1:N2} minutes after global start time {2}.",
this.RouteNumber,
elapsedTime.TotalMilliseconds,
globalStartTime.ToShortTimeString());
}
}

class TestBus
{
static void Main()
{
// The creation of this instance activates the static constructor.
Bus bus1 = new Bus(71);

// Create a second bus.


Bus bus2 = new Bus(72);

// Send bus1 on its way.


bus1.Drive();

// Wait for bus2 to warm up.


System.Threading.Thread.Sleep(25);

// Send bus2 on its way.


bus2.Drive();

// Keep the console window open in debug mode.


System.Console.WriteLine("Press any key to exit.");
System.Console.ReadKey();
}
}
/* Sample output:
Static constructor sets global start time to 3:57:08 PM.
Bus #71 is created.
Bus #72 is created.
71 is starting its route 6.00 minutes after global start time 3:57 PM.
72 is starting its route 31.00 minutes after global start time 3:57 PM.
*/
Vea tambin
Gua de programacin de C#
Clases y estructuras
Constructors (Constructores [Gua de programacin de C#])
Clases estticas y sus miembros
Finalizadores
Cmo: Escribir un constructor Copy (Gua de
programacin de C#)
03/10/2017 1 min to read Edit Online

C# no proporciona un constructor de copias para los objetos, pero puede escribir uno personalmente.

Ejemplo
En el ejemplo siguiente, Person class define un constructor de copias que toma, como argumento, una instancia de
Person . Los valores de las propiedades de los argumentos se asignan a las propiedades de la nueva instancia de
Person . El cdigo contiene un constructor de copias alternativo que enva las propiedades Name y Age de la
instancia que quiere copiar al constructor de instancia de la clase.
class Person
{
// Copy constructor.
public Person(Person previousPerson)
{
Name = previousPerson.Name;
Age = previousPerson.Age;
}

//// Alternate copy constructor calls the instance constructor.


//public Person(Person previousPerson)
// : this(previousPerson.Name, previousPerson.Age)
//{
//}

// Instance constructor.
public Person(string name, int age)
{
Name = name;
Age = age;
}

public int Age { get; set; }

public string Name { get; set; }

public string Details()


{
return Name + " is " + Age.ToString();
}
}

class TestPerson
{
static void Main()
{
// Create a Person object by using the instance constructor.
Person person1 = new Person("George", 40);

// Create another Person object, copying person1.


Person person2 = new Person(person1);

// Change each person's age.


person1.Age = 39;
person2.Age = 41;

// Change person2's name.


person2.Name = "Charles";

// Show details to verify that the name and age fields are distinct.
Console.WriteLine(person1.Details());
Console.WriteLine(person2.Details());

// Keep the console window open in debug mode.


Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
// Output:
// George is 39
// Charles is 41

Vea tambin
ICloneable
Gua de programacin de C#
Clases y estructuras
Constructors (Constructores [Gua de programacin de C#])
Finalizadores
Finalizadores (Gua de programacin de C#)
03/10/2017 3 min to read Edit Online

Los finalizadores se usan para destruir instancias de clases.

Comentarios
Los finalizadores no se pueden definir en structs. Solo se usan con clases.
Una clase solo puede tener un finalizador.
Los finalizadores no se pueden heredar ni sobrecargar.
No se puede llamar a los finalizadores. Se invocan automticamente.
Un finalizador no permite modificadores ni tiene parmetros.
Por ejemplo, el siguiente cdigo muestra una declaracin de un finalizador para la clase Car .

class Car
{
~Car() // destructor
{
// cleanup statements...
}
}

Un finalizador tambin puede implementarse como una definicin de cuerpo de expresin, como se muestra en
el ejemplo siguiente.

using System;

public class Destroyer


{
public override string ToString() => GetType().Name;

~Destroyer() => Console.WriteLine($"The {ToString()} destructor is executing.");


}

El finalizador llama implcitamente a Finalize en la clase base del objeto. Por lo tanto, una llamada a un
finalizador se convierte implcitamente al siguiente cdigo:

protected override void Finalize()


{
try
{
// Cleanup statements...
}
finally
{
base.Finalize();
}
}

Esto significa que se realizan llamadas al mtodo Finalize de manera recursiva para todas las instancias de la
cadena de herencia, desde la ms a la menos derivada.

NOTA
Los finalizadores vacos no deben usarse. Cuando una clase contiene un finalizador, se crea una entrada en la cola
Finalize . Cuando se llama al finalizador, se invoca al recolector de elementos no utilizados para procesar la cola. Un
finalizador vaco simplemente produce una prdida de rendimiento innecesaria.

El programador no puede controlar cundo se llama al finalizador, porque esto lo determina el recolector de
elementos no utilizados. El recolector de elementos no utilizados comprueba si hay objetos que ya no estn
siendo usados por ninguna aplicacin. Si considera un objeto elegible para su finalizacin, llama al finalizador (si
existe) y reclama la memoria usada para almacenar el objeto. Tambin se llama a los finalizadores cuando se
cierra el programa.
Es posible forzar la recoleccin de elementos no utilizados llamando a Collect, pero en general debe evitarse su
uso por razones de rendimiento.

Usar finalizadores para liberar recursos


En general, C# no requiere tanta administracin de memoria como se necesita al desarrollar con un lenguaje que
no est diseado para un runtime con recoleccin de elementos no utilizados. Esto es debido a que el recolector
de elementos no utilizados de .NET Framework administra implcitamente la asignacin y liberacin de memoria
para los objetos. En cambio, cuando la aplicacin encapsule recursos no administrados como ventanas, archivos
y conexiones de red, debera usar finalizadores para liberar dichos recursos. Cuando el objeto cumple los
requisitos para su finalizacin, el recolector de elementos no utilizados ejecuta el mtodo Finalize del objeto.

Liberacin explcita de recursos


Si la aplicacin usa un recurso externo costoso, tambin es recomendable liberar explcitamente el recurso antes
de que el recolector de elementos no utilizados libere el objeto. Para ello debe implementar un mtodo Dispose
desde la interfaz IDisposable que realiza la limpieza del objeto necesaria. Esto puede mejorar considerablemente
el rendimiento de la aplicacin. Aunque controle explcitamente los recursos, el finalizador garantiza la liberacin
de recursos si la llamada al mtodo Dispose genera un error.
Para obtener ms detalles sobre la liberacin de recursos, vea los siguientes temas:
Limpieza de recursos no administrados
Implementacin de un mtodo Dispose
using (instruccin)

Ejemplo
En el siguiente ejemplo se crean tres clases que forman una cadena de herencia. La clase First es la clase base,
Second se deriva de First y Third se deriva de Second . Los tres tienen finalizadores. En Main , se crea una
instancia de la clase ms derivada. Cuando ejecute el programa, observe que se llama a los finalizadores de las
tres clases automticamente y en orden, desde la ms derivada hasta la menos derivada.
class First
{
~First()
{
System.Diagnostics.Trace.WriteLine("First's destructor is called.");
}
}

class Second : First


{
~Second()
{
System.Diagnostics.Trace.WriteLine("Second's destructor is called.");
}
}

class Third : Second


{
~Third()
{
System.Diagnostics.Trace.WriteLine("Third's destructor is called.");
}
}

class TestDestructors
{
static void Main()
{
Third t = new Third();
}

}
/* Output (to VS Output Window):
Third's destructor is called.
Second's destructor is called.
First's destructor is called.
*/

Especificacin del lenguaje C#


Para obtener ms informacin, consulte la Especificacin del lenguaje C#. La especificacin del lenguaje es la
fuente definitiva de la sintaxis y el uso de C#.

Vea tambin
IDisposable
Gua de programacin de C#
Constructores
Recoleccin de elementos no utilizados
Inicializadores de objeto y de coleccin (Gua de
programacin de C#)
03/10/2017 4 min to read Edit Online

Los inicializadores de objeto permiten asignar valores a cualquier campo o propiedad accesible de un objeto en el
momento de su creacin sin tener que invocar un constructor seguido de lneas de instrucciones de asignacin. La
sintaxis de inicializador de objetos permite especificar argumentos para un constructor u omitir los argumentos (y
la sintaxis de parntesis). En el ejemplo siguiente se muestra cmo usar un inicializador de objeto con un tipo con
nombre, Cat , y cmo invocar el constructor predeterminado. Tenga en cuenta el uso de propiedades
implementadas automticamente en la clase Cat . Para obtener ms informacin, vea Auto-Implemented
Properties (Propiedades implementadas automticamente).

class Cat
{
// Auto-implemented properties.
public int Age { get; set; }
public string Name { get; set; }
}

Cat cat = new Cat { Age = 10, Name = "Fluffy" };

Inicializadores de objeto con tipos annimos


Aunque los inicializadores de objeto se pueden usar en cualquier contexto, resultan especialmente tiles en las
expresiones de consulta LINQ. Las expresiones de consulta usan con frecuencia tipos annimos, que solo se
pueden inicializar con un inicializador de objeto, como se muestra en la siguiente declaracin.

var pet = new { Age = 10, Name = "Fluffy" };

Los tipos annimos permiten a la clusula select de una expresin de consulta LINQ transformar objetos de la
secuencia original en objetos cuyo valor y forma pueden ser distintos de los originales. Esto resulta til si desea
almacenar solo una parte de la informacin de cada objeto en una secuencia. En el ejemplo siguiente, suponga
que un objeto del producto ( p ) contiene numerosos campos y mtodos y que solo le interesa crear una
secuencia de objetos que contenga el nombre del producto y el precio por unidad.

var productInfos =
from p in products
select new { p.ProductName, p.UnitPrice };

Al ejecutarse esta consulta, la variable productInfos incluir una secuencia de objetos a la que se puede tener
acceso en una instruccin foreach , como se muestra en este ejemplo:

foreach(var p in productInfos){...}

Cada uno de los objetos del nuevo tipo annimo tiene dos propiedades pblicas que reciben los mismos nombres
que las propiedades o campos del objeto original. Tambin puede cambiar el nombre de un campo al crear un
tipo annimo; en el ejemplo siguiente se cambia el nombre del campo UnitPrice a Price .

select new {p.ProductName, Price = p.UnitPrice};

Inicializadores de objeto con tipos que aceptan valores NULL


Es un error en tiempo de compilacin usar un inicializador de objeto con un struct que acepta valores NULL.

Inicializadores de coleccin
Los inicializadores de coleccin le permiten especificar uno o varios inicializadores de elemento al inicializar un
tipo de coleccin que implementa IEnumerable y tiene Add con la firma apropiada como un mtodo de instancia
o un mtodo de extensin. Los inicializadores de elemento pueden ser un valor simple, una expresin o un
inicializador de objeto. Si se usa un inicializador de coleccin, no es necesario especificar varias llamadas al
mtodo Add de la clase en el cdigo fuente; el compilador agrega las llamadas.
En los ejemplos siguientes se muestran dos inicializadores de coleccin simples:

List<int> digits = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };


List<int> digits2 = new List<int> { 0 + 1, 12 % 3, MakeInt() };

El inicializador de coleccin siguiente usa inicializadores de objeto para inicializar los objetos de la clase Cat
definida en un ejemplo anterior. Observe que los inicializadores de objeto individuales se escriben entre llaves y
se separan por comas.

List<Cat> cats = new List<Cat>


{
new Cat(){ Name = "Sylvester", Age=8 },
new Cat(){ Name = "Whiskers", Age=2 },
new Cat(){ Name = "Sasha", Age=14 }
};

Puede especificar null como elemento de un inicializador de coleccin si el mtodo Add de la coleccin lo
permite.

List<Cat> moreCats = new List<Cat>


{
new Cat(){ Name = "Furrytail", Age=5 },
new Cat(){ Name = "Peaches", Age=4 },
null
};

Puede especificar elementos indexados si la coleccin admite la indexacin.

var numbers = new Dictionary<int, string> {


[7] = "seven",
[9] = "nine",
[13] = "thirteen"
};

Ejemplo
// The following code consolidates examples from the topic.
class ObjInitializers
{
class Cat
{
// Auto-implemented properties.
public int Age { get; set; }
public string Name { get; set; }
}

static void Main()


{
Cat cat = new Cat { Age = 10, Name = "Fluffy" };

List<Cat> cats = new List<Cat>


{
new Cat(){ Name = "Sylvester", Age=8 },
new Cat(){ Name = "Whiskers", Age=2 },
new Cat(){ Name = "Sasha", Age=14 }
};

List<Cat> moreCats = new List<Cat>


{
new Cat(){ Name = "Furrytail", Age=5 },
new Cat(){ Name = "Peaches", Age=4 },
null
};

// Display results.
System.Console.WriteLine(cat.Name);

foreach (Cat c in cats)


System.Console.WriteLine(c.Name);

foreach (Cat c in moreCats)


if (c != null)
System.Console.WriteLine(c.Name);
else
System.Console.WriteLine("List element has null value.");
}
// Output:
//Fluffy
//Sylvester
//Whiskers
//Sasha
//Furrytail
//Peaches
//List element has null value.
}

Vea tambin
Gua de programacin de C#
Expresiones de consulta LINQ
Tipos annimos
Cmo: Inicializar objetos usando un inicializador de
objeto (Gua de programacin de C#)
03/10/2017 2 min to read Edit Online

Puede usar inicializadores de objeto para inicializar objetos de tipo de una forma declarativa sin tener que invocar
explcitamente un constructor para el tipo.
En los siguientes ejemplos se muestra cmo usar los inicializadores de objeto con objetos con nombre. El
compilador procesa los inicializadores de objeto primero obteniendo acceso al constructor de instancia
predeterminado y despus procesando las inicializaciones de miembro. Por lo tanto, si el constructor
predeterminado se declara como private en la clase, se producir un error en los inicializadores de objeto que
requieren acceso pblico.
Debe usar un inicializador de objeto si va a definir un tipo annimo. Para obtener ms informacin, vea Cmo:
Devolver subconjuntos de propiedades de elementos en una consulta.

Ejemplo
En el siguiente ejemplo se muestra cmo inicializar un nuevo tipo StudentName usando inicializadores de objeto.

public class Program


{
public static void Main()
{

// Declare a StudentName by using the constructor that has two parameters.


StudentName student1 = new StudentName("Craig", "Playstead");

// Make the same declaration by using an object initializer and sending


// arguments for the first and last names. The default constructor is
// invoked in processing this declaration, not the constructor that has
// two parameters.
StudentName student2 = new StudentName
{
FirstName = "Craig",
LastName = "Playstead",
};

// Declare a StudentName by using an object initializer and sending


// an argument for only the ID property. No corresponding constructor is
// necessary. Only the default constructor is used to process object
// initializers.
StudentName student3 = new StudentName
{
ID = 183
};

// Declare a StudentName by using an object initializer and sending


// arguments for all three properties. No corresponding constructor is
// defined in the class.
StudentName student4 = new StudentName
{
FirstName = "Craig",
LastName = "Playstead",
ID = 116
};

System.Console.WriteLine(student1.ToString());
System.Console.WriteLine(student1.ToString());
System.Console.WriteLine(student2.ToString());
System.Console.WriteLine(student3.ToString());
System.Console.WriteLine(student4.ToString());
}

// Output:
// Craig 0
// Craig 0
// 183
// Craig 116
}

public class StudentName


{
// The default constructor has no parameters. The default constructor
// is invoked in the processing of object initializers.
// You can test this by changing the access modifier from public to
// private. The declarations in Main that use object initializers will
// fail.
public StudentName() { }

// The following constructor has parameters for two of the three


// properties.
public StudentName(string first, string last)
{
FirstName = first;
LastName = last;
}

// Properties.
public string FirstName { get; set; }
public string LastName { get; set; }
public int ID { get; set; }

public override string ToString()


{
return FirstName + " " + ID;
}
}

Ejemplo
En el siguiente ejemplo se muestra cmo inicializar una coleccin de tipos StudentName usando un inicializador de
coleccin. Tenga en cuenta que un inicializador de coleccin es una serie de inicializadores de objeto separados por
comas.

List<StudentName> students = new List<StudentName>()


{
new StudentName {FirstName="Craig", LastName="Playstead", ID=116},
new StudentName {FirstName="Shu", LastName="Ito", ID=112},
new StudentName {FirstName="Gretchen", LastName="Rivas", ID=113},
new StudentName {FirstName="Rajesh", LastName="Rotti", ID=114}
};

Compilar el cdigo
Para ejecutar este cdigo, copie y pegue la clase en un proyecto de aplicacin de consola de Visual C# creado en
Visual Studio.

Vea tambin
Gua de programacin de C#
Inicializadores de objeto y coleccin
Cmo: Inicializar un diccionario con un inicializador
de coleccin (Gua de programacin de C#)
03/10/2017 1 min to read Edit Online

Un mtodo Dictionary<TKey,TValue> contains a collection of key/value pairs. Its Add acepta dos parmetros, uno
para la clave y otro para el valor. Para inicializar un mtodo Dictionary<TKey,TValue>, or any collection whose Add
que acepte varios parmetros, encierre entre llaves cada uno de los conjuntos de parmetros, como se muestra en
el ejemplo siguiente.

Ejemplo
En el ejemplo de cdigo siguiente, Dictionary<TKey,TValue> is initialized with instances of type StudentName .

class StudentName
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int ID { get; set; }
}

class CollInit
{
Dictionary<int, StudentName> students = new Dictionary<int, StudentName>()
{
{ 111, new StudentName {FirstName="Sachin", LastName="Karnik", ID=211}},
{ 112, new StudentName {FirstName="Dina", LastName="Salimzianova", ID=317}},
{ 113, new StudentName {FirstName="Andy", LastName="Ruth", ID=198}}
};
}

Observe los dos pares de llaves en cada elemento de la coleccin. Las llaves internas contienen el inicializador de
objeto para StudentName y las llaves externas contienen el inicializador para el par clave-valor que se agregar a
students Dictionary<TKey,TValue>. Por ltimo, el inicializador completo de la coleccin para el diccionario se
encierra entre llaves.

Compilar el cdigo
Para ejecutar este cdigo, copie y pegue la clase en un proyecto de aplicacin de consola de Visual C# creado en
Visual Studio. De manera predeterminada, el proyecto tiene como destino la versin 3.5 de .NET Framework y
contiene una referencia a System.Core.dll y una directiva using para System.Linq. Si faltan uno o varios de estos
requisitos del proyecto, puede agregarlos manualmente.

Vea tambin
Gua de programacin de C#
Inicializadores de objeto y coleccin
Cmo: Obtener acceso a una clase de coleccin
mediante Foreach (Gua de programacin de C#)
03/10/2017 3 min to read Edit Online

En el ejemplo de cdigo siguiente se muestra cmo se escribe una clase Collection no genrica que se puede usar
con la instruccin foreach. En el ejemplo se define una clase de tokenizador de cadenas.

NOTA
En este ejemplo se representa el procedimiento recomendado solo cuando no se puede usar una clase Collection genrica.
Para obtener un ejemplo de cmo se implementa una clase de coleccin genrica con seguridad de tipos que admita
IEnumerable<T>, vea Iteradores.

En el ejemplo, el siguiente segmento de cdigo usa la clase Tokens para dividir la frase "This is a sample sentence."
en tokens usando " " y "-" como separadores. Despus, el cdigo muestra esos tokens mediante una instruccin
foreach .

Tokens f = new Tokens("This is a sample sentence.", new char[] {' ','-'});

// Display the tokens.


foreach (string item in f)
{
System.Console.WriteLine(item);
}

Ejemplo
Internamente, la clase Tokens usa una matriz para almacenar los tokens. Como las matrices implementan
IEnumerator y IEnumerable, el ejemplo de cdigo podra haber usado los mtodos de enumeracin de la matriz
(GetEnumerator, MoveNext, Reset y Current) en lugar de definirlos en la clase Tokens . Las definiciones de los
mtodos se incluyen en el ejemplo para clarificar cmo estn definidos y qu hace cada uno.

using System.Collections;

// Declare the Tokens class. The class implements the IEnumerable interface.
public class Tokens : IEnumerable
{
private string[] elements;

Tokens(string source, char[] delimiters)


{
// The constructor parses the string argument into tokens.
elements = source.Split(delimiters);
}

// The IEnumerable interface requires implementation of method GetEnumerator.


public IEnumerator GetEnumerator()
{
return new TokenEnumerator(this);
}

// Declare an inner class that implements the IEnumerator interface.


private class TokenEnumerator : IEnumerator
private class TokenEnumerator : IEnumerator
{
private int position = -1;
private Tokens t;

public TokenEnumerator(Tokens t)
{
this.t = t;
}

// The IEnumerator interface requires a MoveNext method.


public bool MoveNext()
{
if (position < t.elements.Length - 1)
{
position++;
return true;
}
else
{
return false;
}
}

// The IEnumerator interface requires a Reset method.


public void Reset()
{
position = -1;
}

// The IEnumerator interface requires a Current method.


public object Current
{
get
{
return t.elements[position];
}
}
}

// Test the Tokens class.


static void Main()
{
// Create a Tokens instance.
Tokens f = new Tokens("This is a sample sentence.", new char[] {' ','-'});

// Display the tokens.


foreach (string item in f)
{
System.Console.WriteLine(item);
}
}
}
/* Output:
This
is
a
sample
sentence.
*/

En C#, no es necesario para una clase de coleccin implementar IEnumerable y IEnumerator para que sean
compatibles con foreach . Si la clase tiene los miembros GetEnumerator, MoveNext, Reset y Current necesarios,
funcionar con foreach . Omitir las interfaces tiene la ventaja de que permite definir un tipo de valor devuelto de
Current que es ms especfico que Object. Esto proporciona seguridad de tipos.
Por ejemplo, cambie las siguientes lneas del ejemplo anterior.

// Change the Tokens class so that it no longer implements IEnumerable.


public class Tokens
{
// . . .

// Change the return type for the GetEnumerator method.


public TokenEnumerator GetEnumerator()
{ }

// Change TokenEnumerator so that it no longer implements IEnumerator.


public class TokenEnumerator
{
// . . .

// Change the return type of method Current to string.


public string Current
{ }
}
}

Dado que Current devuelve una cadena, el compilador puede detectar cundo se usa un tipo incompatible en una
instruccin foreach , como se muestra en el cdigo siguiente.

// Error: Cannot convert type string to int.


foreach (int item in f)

El inconveniente de omitir IEnumerable y IEnumerator es que la clase de coleccin ya no puede interactuar con las
instrucciones foreach (o equivalentes) de otros lenguajes compatibles con Common Language Runtime.

Vea tambin
System.Collections.Generic
Referencia de C#
Gua de programacin de C#
Arrays (Matrices)
Colecciones
Tipos anidados (Gua de programacin de C#)
03/10/2017 1 min to read Edit Online

Un tipo definido en una clase o struct se denomina tipo anidado. Por ejemplo:

class Container
{
class Nested
{
Nested() { }
}
}

Con independencia de si el tipo externo es una clase o struct, los tipos anidados se establecen de manera
predeterminada en private, solo son accesibles desde su tipo contenedor. En el ejemplo anterior, la clase Nested
es inaccesible a los tipos externos.
Tambin puede especificar un modificador de acceso para definir la accesibilidad de un tipo anidado, de la manera
siguiente:
Los tipos anidados de una clase pueden ser public, protected, internal, protected internal o private.
En cambio, al definir una clase anidada protected o protected internal dentro de una clase sellada genera
una advertencia del compilador CS0628, "Nuevo miembro protegido declarado en la clase sealed".
Los tipos anidados de un struct pueden ser public, internal o private.
En el ejemplo siguiente se convierte la clase Nested en public:

class Container
{
public class Nested
{
Nested() { }
}
}

El tipo anidado o interno puede tener acceso al tipo contenedor o externo. Para tener acceso al tipo contenedor,
pselo como un argumento al constructor del tipo anidado. Por ejemplo:

public class Container


{
public class Nested
{
private Container parent;

public Nested()
{
}
public Nested(Container parent)
{
this.parent = parent;
}
}
}
Un tipo anidado tiene acceso a todos los miembros que estn accesibles para el tipo contenedor. Puede tener
acceso a los miembros privados y protegidos del tipo contenedor, incluidos los miembros protegidos heredados.
En la declaracin anterior, el nombre completo de la clase Nested es Container.Nested . Este es el nombre que se
utiliza para crear una instancia nueva de la clase anidada, de la siguiente manera:

Container.Nested nest = new Container.Nested();

Vea tambin
Gua de programacin de C#
Clases y structs
Modificadores de acceso
Constructores
Clases y mtodos parciales (Gua de programacin de
C#)
03/10/2017 7 min to read Edit Online

Es posible dividir la definicin de una clase o un struct, una interfaz o un mtodo en dos o ms archivos de cdigo
fuente. Cada archivo de cdigo fuente contiene una seccin de la definicin de tipo o mtodo, y todos los
elementos se combinan cuando se compila la aplicacin.

Clases parciales
Es recomendable dividir una definicin de clase en varias situaciones:
Cuando se trabaja con proyectos grandes, el hecho de repartir una clase entre archivos independientes
permite que varios programadores trabajen en ella al mismo tiempo.
Cuando se trabaja con cdigo fuente generado automticamente, se puede agregar cdigo a la clase sin
tener que volver a crear el archivo de cdigo fuente. Visual Studio usa este enfoque al crear formularios
Windows Forms, cdigo de contenedor de servicio Web, etc. Puede crear cdigo que use estas clases sin
necesidad de modificar el archivo creado por Visual Studio.
Para dividir una definicin de clase, use el modificador de palabra clave partial, como se muestra aqu:

public partial class Employee


{
public void DoWork()
{
}
}

public partial class Employee


{
public void GoToLunch()
{
}
}

La palabra clave partial indica que se pueden definir en el espacio de nombres otros elementos de la clase, la
estructura o la interfaz. Todos los elementos deben usar la palabra clave partial . Todos los elementos deben estar
disponibles en tiempo de compilacin para formar el tipo final. Todos los elementos deben tener la misma
accesibilidad, como public , private , etc.
Si algn elemento se declara abstracto, todo el tipo se considera abstracto. Si algn elemento se declara sellado,
todo el tipo se considera sellado. Si algn elemento declara un tipo base, todo el tipo hereda esa clase.
Todos los elementos que especifiquen una clase base deben coincidir, pero los elementos que omitan una clase
base heredan igualmente el tipo base. Los elementos pueden especificar diferentes interfaces base, y el tipo final
implementa todas las interfaces enumeradas por todas las declaraciones parciales. Todas las clases, structs o
miembros de interfaz declarados en una definicin parcial estn disponibles para todos los dems elementos. El
tipo final es la combinacin de todos los elementos en tiempo de compilacin.
NOTA
El modificador partial no est disponible en declaraciones de delegado o enumeracin.

En el ejemplo siguiente se muestra que los tipos anidados pueden ser parciales, incluso si el tipo en el que estn
anidados no es parcial.

class Container
{
partial class Nested
{
void Test() { }
}
partial class Nested
{
void Test2() { }
}
}

En tiempo de compilacin, se combinan los atributos de definiciones de tipo parcial. Por ejemplo, consideremos las
siguientes declaraciones:

[SerializableAttribute]
partial class Moon { }

[ObsoleteAttribute]
partial class Moon { }

Son equivalentes a las declaraciones siguientes:

[SerializableAttribute]
[ObsoleteAttribute]
class Moon { }

A continuacin se indican los elementos que se combinan de todas las definiciones de tipo parcial:
comentarios XML
interfaces
atributos de parmetro de tipo genrico
class (atributos)
miembros
Por ejemplo, consideremos las siguientes declaraciones:

partial class Earth : Planet, IRotate { }


partial class Earth : IRevolve { }

Son equivalentes a las declaraciones siguientes:

class Earth : Planet, IRotate, IRevolve { }

Restricciones
Debe seguir varias reglas al trabajar con definiciones de clase parcial:
Todas las definiciones de tipo parcial que van a formar parte del mismo tipo deben modificarse con
partial . Por ejemplo, las declaraciones de clase siguientes generan un error:

public partial class A { }


//public class A { } // Error, must also be marked partial

El modificador partial solo puede aparecer inmediatamente antes de las palabras clave class , struct o
interface .

Se permiten tipos parciales anidados en definiciones de tipo parcial, como se muestra en el ejemplo
siguiente:

partial class ClassWithNestedClass


{
partial class NestedClass { }
}

partial class ClassWithNestedClass


{
partial class NestedClass { }
}

Todas las definiciones de tipo parcial que van a formar parte del mismo tipo deben definirse en el mismo
ensamblado y en el mismo mdulo (archivo .exe o .dll). Las definiciones parciales no pueden abarcar varios
mdulos.
El nombre de clase y los parmetros de tipo genrico deben coincidir en todas las definiciones de tipo
parcial. Los tipos genricos pueden ser parciales. Cada declaracin parcial debe usar los mismos nombres
de parmetro en el mismo orden.
Las siguientes palabras clave son opcionales en una definicin de tipo parcial, pero si estn presentes la
definicin, no pueden entrar en conflicto con las palabras clave especificadas en otra definicin parcial para
el mismo tipo:
public
private
protected
internal
abstract
sealed
clase base
modificador new (elementos anidados)
restricciones genricas
Para obtener ms informacin, vea Restricciones de tipos de parmetros.

Ejemplo 1
Descripcin
En el ejemplo siguiente, los campos y el constructor de la clase, CoOrds , se declaran en una definicin de clase
parcial y el miembro PrintCoOrds se declara en otra definicin de clase parcial.
Cdigo

public partial class CoOrds


{
private int x;
private int y;

public CoOrds(int x, int y)


{
this.x = x;
this.y = y;
}
}

public partial class CoOrds


{
public void PrintCoOrds()
{
Console.WriteLine("CoOrds: {0},{1}", x, y);
}

class TestCoOrds
{
static void Main()
{
CoOrds myCoOrds = new CoOrds(10, 15);
myCoOrds.PrintCoOrds();

// Keep the console window open in debug mode.


Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
// Output: CoOrds: 10,15

Ejemplo 2
Descripcin
En el ejemplo siguiente se muestra que tambin se pueden desarrollar structs e interfaces parciales.
Cdigo
partial interface ITest
{
void Interface_Test();
}

partial interface ITest


{
void Interface_Test2();
}

partial struct S1
{
void Struct_Test() { }
}

partial struct S1
{
void Struct_Test2() { }
}

Mtodos Partial
Una clase o struct parcial puede contener un mtodo parcial. Un elemento de la clase contiene la firma del mtodo.
Se puede definir una implementacin opcional en el mismo elemento o en otro. Si no se proporciona la
implementacin, el mtodo y todas las llamadas al mtodo se quitan en tiempo de compilacin.
Los mtodos parciales permiten que el implementador de un elemento de una clase defina un mtodo, similar a un
evento. El implementador del otro elemento de la clase puede decidir si quiere implementar el mtodo o no. Si el
mtodo no se implementa, el compilador quita la firma del mtodo y todas las llamadas al mtodo. Las llamadas al
mtodo, incluidos los resultados que se produciran por la evaluacin de los argumentos de las llamadas, no tienen
efecto en tiempo de ejecucin. Por lo tanto, el cdigo de la clase parcial puede usar libremente un mtodo parcial,
incluso si no se proporciona la implementacin. No se producir ningn error en tiempo de compilacin o en
tiempo de ejecucin si se llama al mtodo pero no se implementa.
Los mtodos parciales son especialmente tiles para personalizar el cdigo generado. Permiten reservar un
nombre y firma de mtodo de modo que el cdigo generado pueda llamar al mtodo, pero el desarrollador decide
si se implementa el mtodo. De manera muy similar a como hacen las clases parciales, los mtodos parciales
permiten que el cdigo creado por un generador de cdigo y el cdigo creado por un desarrollador humano
funcionen juntos sin costos en tiempo de ejecucin.
Una declaracin de mtodo parcial consta de dos elementos: la definicin y la implementacin. Pueden encontrarse
en elementos independientes de una clase parcial o en el mismo elemento. Si no hay ninguna declaracin de
implementacin, el compilador optimiza tanto la declaracin de definicin como todas las llamadas al mtodo.

// Definition in file1.cs
partial void onNameChanged();

// Implementation in file2.cs
partial void onNameChanged()
{
// method body
}

Las declaraciones de mtodo parcial deben comenzar con la palabra clave contextual partial y el mtodo
debe devolver void.
Los mtodos parciales pueden tener parmetros ref, pero no parmetros out.
Los mtodos parciales son implcitamente private y, por tanto, no pueden ser virtual.
Los mtodos parciales no pueden ser extern, ya que la presencia del cuerpo determina si son de definicin o
de implementacin.
Los mtodos parciales pueden tener modificadores static y unsafe.
Los mtodos parciales pueden ser genricos. Las restricciones se colocan en la declaracin de mtodo
parcial de definicin y opcionalmente pueden repetirse en el de implementacin. Los nombres del
parmetro y del parmetro de tipo no tienen que ser iguales en la declaracin de implementacin y en la
declaracin de definicin.
Puede crear un delegado para un mtodo parcial que se ha definido e implementado, pero no para un
mtodo parcial que solo se ha definido.

Especificacin del lenguaje C#


Para obtener ms informacin, consulte la Especificacin del lenguaje C#. La especificacin del lenguaje es la
fuente definitiva de la sintaxis y el uso de C#.

Vea tambin
Gua de programacin de C#
Clases
Structs
Interfaces
partial (Tipos)
Tipos annimos (Gua de programacin de C#)
03/10/2017 4 min to read Edit Online

Los tipos annimos son una manera cmoda de encapsular un conjunto de propiedades de solo lectura en un
nico objeto sin tener que definir primero un tipo explcitamente. El compilador genera el nombre del tipo y no
est disponible en el nivel de cdigo fuente. El compilador deduce el tipo de cada propiedad.
Para crear tipos annimos, use el operador new con un inicializador de objeto. Para obtener ms informacin
sobre los inicializadores de objeto, vea Inicializadores de objeto y coleccin (Gua de programacin de C#).
En el ejemplo siguiente se muestra un tipo annimo que se inicializa con dos propiedades llamadas Amount y
Message .

var v = new { Amount = 108, Message = "Hello" };

// Rest the mouse pointer over v.Amount and v.Message in the following
// statement to verify that their inferred types are int and string.
Console.WriteLine(v.Amount + v.Message);

Los tipos annimos suelen usarse en la clusula select de una expresin de consulta para devolver un
subconjunto de las propiedades de cada objeto en la secuencia de origen. Para obtener ms informacin sobre
consultas, vea Expresiones de consulta LINQ.
Los tipos annimos contienen una o varias propiedades pblicas de solo lectura. No es vlido ningn otro tipo de
miembros de clase, como mtodos o eventos. La expresin que se usa para inicializar una propiedad no puede ser
null , una funcin annima o un tipo de puntero.

El escenario ms habitual es inicializar un tipo annimo con propiedades de otro tipo. En el siguiente ejemplo, se
da por hecho que existe una clase con el nombre Product . La clase Product incluye las propiedades Color y
Price , junto con otras propiedades que no son de su inters. La variable products es una coleccin de objetos
Product . La declaracin de tipo annimo comienza con la palabra clave new . La declaracin inicializa un nuevo
tipo que solo usa dos propiedades de Product . Esto hace que la consulta devuelva una cantidad de datos menor.
Si no especifica los nombres de miembro en el tipo annimo, el compilador da a los miembros de tipo annimo el
mismo nombre que la propiedad que se usa para inicializarlos. Debe proporcionar un nombre para una
propiedad que se est inicializando con una expresin, como se muestra en el ejemplo anterior. En el siguiente
ejemplo, los nombres de las propiedades del tipo annimo son Color y Price .

var productQuery =
from prod in products
select new { prod.Color, prod.Price };

foreach (var v in productQuery)


{
Console.WriteLine("Color={0}, Price={1}", v.Color, v.Price);
}

Normalmente, cuando se usa un tipo annimo para inicializar una variable, la variable se declara como variable
local con tipo implcito mediante var. El nombre del tipo no se puede especificar en la declaracin de la variable
porque solo el compilador tiene acceso al nombre subyacente del tipo annimo. Para obtener ms informacin
sobre var , vea Variables locales con asignacin implcita de tipos.
Puede crear una matriz de elementos con tipo annimo combinando una variable local con tipo implcito y una
matriz con tipo implcito, como se muestra en el ejemplo siguiente.

var anonArray = new[] { new { name = "apple", diam = 4 }, new { name = "grape", diam = 1 }};

Comentarios
Los tipos annimos son tipos class que derivan directamente de object y que no se pueden convertir a ningn
tipo excepto object. El compilador proporciona un nombre para cada tipo annimo, aunque la aplicacin no pueda
acceder a l. Desde el punto de vista de Common Language Runtime, un tipo annimo no es diferente de otros
tipos de referencia.
Si dos o ms inicializadores de objeto annimo en un ensamblado especifican una secuencia de propiedades que
estn en el mismo orden y que tienen los mismos nombres y tipos, el compilador trata el objeto como instancias
del mismo tipo. Comparten la misma informacin de tipo generada por el compilador.
No se puede declarar que un campo, una propiedad, un evento o el tipo de valor devuelto de un mtodo tengan
un tipo annimo. De forma similar, no se puede declarar que un parmetro formal de un mtodo, propiedad,
constructor o indizador tenga un tipo annimo. Para pasar un tipo annimo, o una coleccin que contiene tipos
annimos, como un argumento a un mtodo, puede declarar el parmetro como objeto de tipo. Sin embargo, al
hacerlo se invalida el propsito del tipado fuerte. Si tiene que almacenar resultados de consulta o pasarlos fuera
del lmite del mtodo, considere la posibilidad de usar un struct o una clase con nombre normal en lugar de un
tipo annimo.
Como los mtodos Equals y GetHashCode de tipos annimos se definen en trminos de los mtodos Equals y
GetHashCode de las propiedades, dos instancias del mismo tipo annimo son iguales solo si todas sus
propiedades son iguales.

Vea tambin
Gua de programacin de C#
Inicializadores de objeto y de coleccin
Introduccin a LINQ en C#
Expresiones de consulta LINQ
Cmo: Devolver subconjuntos de propiedades de
elementos en una consulta (Gua de programacin de
C#)
03/10/2017 1 min to read Edit Online

Use un tipo annimo en una expresin de consulta cuando se cumplan estas dos condiciones:
Solo quiere algunas de las propiedades de cada elemento de origen.
No es necesario almacenar los resultados de la consulta fuera del mbito del mtodo en el que se ejecuta la
consulta.
Si solo quiere devolver una propiedad o campo de cada elemento de origen, puede usar simplemente el operador
de punto en la clusula select . Por ejemplo, para devolver solo el ID de cada student , escriba la clusula
select como sigue:

select student.ID;

Ejemplo
En el ejemplo siguiente se muestra cmo usar un tipo annimo para devolver solo un subconjunto de las
propiedades de cada elemento de origen que coincida con la condicin especificada.

private static void QueryByScore()


{
// Create the query. var is required because
// the query produces a sequence of anonymous types.
var queryHighScores =
from student in students
where student.ExamScores[0] > 95
select new { student.FirstName, student.LastName };

// Execute the query.


foreach (var obj in queryHighScores)
{
// The anonymous type's properties were not named. Therefore
// they have the same names as the Student properties.
Console.WriteLine(obj.FirstName + ", " + obj.LastName);
}
}
/* Output:
Adams, Terry
Fakhouri, Fadi
Garcia, Cesar
Omelchenko, Svetlana
Zabokritski, Eugene
*/

Tenga en cuenta que, si no se especifica ningn nombre, el tipo annimo usa los nombres del elemento de origen
para sus propiedades. Para asignar nombres nuevos a las propiedades del tipo annimo, escriba la instruccin
select como sigue:
select new { First = student.FirstName, Last = student.LastName };

Si lo intenta en el ejemplo anterior, tambin debe cambiar la instruccin Console.WriteLine :

Console.WriteLine(student.First + " " + student.Last);

Compilar el cdigo
Para ejecutar este cdigo, copie y pegue la clase en un proyecto de aplicacin de consola de Visual C# creado en
Visual Studio. De forma predeterminada, este proyecto tiene como destino la versin 3.5 de .NET Framework, y
tendr una referencia a System.Core.dll y una directiva using para System.Linq. Si faltan uno o varios de estos
requisitos del proyecto, se pueden agregar manualmente.

Vea tambin
Gua de programacin de C#
Tipos annimos
Expresiones de consulta LINQ

S-ar putea să vă placă și