Este artículo proviene de un motor de traducción automática.

C# 4,0

Nuevas características de C# en .NET Framework 4

Chris Burrows

Desde su lanzamiento en 2002, el lenguaje de programación de C# se ha mejorado para permitir a los programadores más claro, escribir más código fácil de mantener. Las mejoras proceden de la adición de características, como los tipos genéricos, los tipos de valor que acepta valores NULL, las expresiones lambda, los métodos de iterador, las clases parciales y una larga lista de otras construcciones de lenguaje útiles. Y, a menudo, los cambios se han acompañado con las bibliotecas de Microsoft .NET Framework correspondiente soporte.

Se sigue esta tendencia hacia el aumento de la facilidad de uso en C# 4.0. Las adiciones de realizar tareas comunes que implican a tipos genéricos, interoperabilidad heredada y trabajar con modelos de objeto dinámico mucho más sencillos. En este artículo se pretende dar a una encuesta de alto nivel de estas nuevas características. Va a comenzar con la varianza genérico y, a continuación, examine las características de interoperabilidad heredadas y dinámicas.

Covarianza y contravarianza

Covarianza y contravarianza se presentan mejor con un ejemplo y lo mejor es en el marco de trabajo. En System.Collections.Generic, IEnumerable <T> e IEnumerator <T> representan, respectivamente, un objeto que es una secuencia de T y el enumerador (o iterador) que realiza el trabajo de recorrer en iteración la secuencia. Estas interfaces han hecho una gran cantidad de trabajo durante mucho tiempo, ya que admiten la implementación de la construcción de bucle foreach. En C# 3.0, era incluso más destacadas causa de su función central en LINQ y LINQ to Objects, que son las interfaces de .NET para representar secuencias.

¿Por lo tanto, si tiene una jerarquía de clases con, por ejemplo, un tipo de empleado y Administrador de un tipo que se deriva de ella (los administradores son los empleados, después de todo), a continuación, lo esperaría el siguiente código para hacer?

IEnumerable<Manager> ms = GetManagers();
IEnumerable<Employee> es = ms;

Parece como si uno debe ser capaz de tratar una secuencia de los administradores como si fuese una secuencia de los empleados. Pero en C# 3.0, se producirá un error la asignación; el compilador le avisará que no hay ninguna conversión. Después de todo, no tiene sabe cuáles es la semántica de IEnumerable <T>. Puede tratarse de cualquier interfaz, por lo que para cualquier interfaz IFoo <T> arbitrario, ¿por qué un IFoo <Manager> sería más o menos sustituibles para un IFoo <Employee>?

En C# 4.0, no obstante, la asignación funciona porque IEnumerable <T>, junto con algunas otras interfaces, ha cambiado, una alteración habilitada por la nueva compatibilidad de C# para la covarianza de parámetros de tipo.

IEnumerable <T> es puede ser más especial que el IFoo arbitrario <T> porque, aunque no resulta obvio a primera vista, los miembros que utilizan el parámetro de tipo T (GetEnumerator en IEnumerable <T>) y la propiedad Current en IEnumerator <T> utilizan T sólo en la posición de un valor devuelto. Por lo tanto, sólo obtendrá un administrador de la secuencia, y nunca coloque uno en.

En cambio, piense en lista <T>. Hacer que una lista <Manager> sustituibles para una lista de <Employee> sería un desastre, porque de lo siguiente:

List<Manager> ms = GetManagers();
List<Employee> es = ms; // Suppose this were possible
es.Add(new EmployeeWhoIsNotAManager()); // Uh oh

Tal como se muestra, una vez que cree que está viendo una lista de <Employee>, puede insertar a cualquier empleado. Pero la lista en cuestión es realmente una lista <Manager>, por lo que debe insertar un Manager-no producirá un error. Se ha perdido la seguridad de tipos si lo permite. Lista <T> no puede ser devueltos de covariante en T.

La nueva característica de lenguaje de C# 4.0, a continuación, es la capacidad para definir los tipos, como, por ejemplo, el nuevo IEnumerable <T>, que admiten las conversiones entre sí cuando los parámetros de tipo en cuestión tenga alguna relación entre sí. Esto es lo que los desarrolladores de .NET Framework que se escribieron IEnumerable <T> utilizada, y esto es lo que su código es similar a (por supuesto, simplificado):

public interface IEnumerable<out T> { /* ... */ }

Observe la palabra de clave modificar la definición del tipo de parámetro, T. Cuando el compilador ve esto, se Mark T como covariante y compruebe que, en la definición de la interfaz, todos los usos de T son hacia arriba de snuff (en otras palabras, que se usan en posiciones sólo; por este motivo se ha realizado el picking de esta palabra clave).

¿Por qué es esto llama a la covarianza? Bueno, es más fácil ver cuándo empieza a dibujar flechas. Para ser concretas, utilice let’s los tipos de Manager y Employee. Debido a que hay una relación de herencia entre estas clases, hay una conversión implícita de referencia del Administrador de empleado:

Administrador → empleado

Y, a continuación, debido a de la anotación de T en IEnumerable < fuera T >, también hay una conversión implícita de referencia de IEnumerable <Manager> IEnumerable <Employee>. Eso es lo que proporciona la anotación para:

IEnumerable <Manager> → IEnumerable <Employee>

Esto se denomina la covarianza, porque las flechas situadas en cada uno de los dos ejemplos que se seleccione en la misma dirección. Comenzamos con dos tipos, Manager y Employee. Hemos nuevos tipos de ellos, <Manager> de IEnumerable y IEnumerable <Employee>. Los nuevos tipos de conversión la misma manera que los anteriores.

Contravarianza es en este caso hacia atrás. Es posible que prevé que esto puede ocurrir cuando el parámetro de tipo T, sólo se utiliza como entrada, y sería adecuado. Por ejemplo, el espacio de nombres contiene una interfaz denominada IComparable <T>, que tiene un método denominado CompareTo:

public interface IComparable<in T> { 
  bool CompareTo(T other); 
}

Si tiene un IComparable <Employee>, debe ser capaz de tratar como si fuese un IComparable <Manager>, porque lo único que puede hacer es poner a empleados en la interfaz. Debido a que un administrador es un empleado, debe poner un administrador trabajar y lo hace. La palabra clave in modifica T en este caso, y este escenario funciona correctamente:

IComparable<Employee> ec = GetEmployeeComparer();
IComparable<Manager> mc = ec;

Esto se denomina contravarianza debido a que la flecha que aparece tiene invertir en este momento:

Administrador → empleado
IComparable <Manager> ← IComparable <Employee>

Por lo tanto, la característica del lenguaje es bastante sencilla resumir: Puede agregar la palabra clave en o cada vez que se define un parámetro de tipo, y si lo hace por lo tanto, le libres conversiones adicionales. No obstante, existen algunas limitaciones.

En primer lugar, esto funciona con las interfaces genéricas y delegados sólo. No puede declarar un parámetro de tipo genérico en una clase o estructura de esta manera. Un método sencillo para racionalizar esto es que los delegados son muy parecido a las interfaces que tienen un solo método y en cualquier caso, las clases a menudo, sería no válidas para este tratamiento debido a los campos de. Puede pensar en cualquier campo de la clase genérica como una entrada y una salida, dependiendo de si escribir en él o leer en él. Si estos campos incluyen los parámetros de tipo, los parámetros pueden ser no covariante ni contravariante.

En segundo lugar, cada vez que tiene una interfaz o delegado con un parámetro de tipo covariante o contravariante, está concedido las conversiones de nuevas en ese tipo únicamente cuando los argumentos de tipo, en el uso de la interfaz (no su definición), son tipos de referencia. Por ejemplo, debido a que int es un tipo de valor, no convierte el objeto IEnumerator <int> IEnumerator <object>, aunque parece que debe:

IEnumerator <int> image: right arrow with slash  IEnumerator <object>

El motivo de este comportamiento es que la conversión debe conservar la representación de tipo. Si se permite la conversión de int a objetos, al llamar a la propiedad Current del resultado) sería imposible, debido a que el valor de tipo int tiene una representación diferente en la pila que una referencia de objeto. Todos los tipos de referencia tienen la misma representación en la pila, sin embargo, por lo que sólo los argumentos de tipo que son tipos de referencia producen estas conversiones adicionales.

Muy probablemente, la mayoría de los desarrolladores de C# felizmente utilizará esta nueva característica de lenguaje, obtendrá más conversiones de tipos de marco de trabajo y el número de errores del compilador cuando se utiliza en algunos tipos de .NET Framework (IEnumerable <T>, IComparable <T>, Func <T>, acción <T>, entre otros). Y, de hecho, cualquier persona que diseña una biblioteca con las interfaces genéricas y delegados es utilizar la nueva dentro y hacia fuera de los parámetros de tipo cuando sea apropiado para facilitar la vida de los usuarios.

Por cierto, esta característica requiere compatibilidad con el tiempo de ejecución, pero el soporte técnico siempre ha sido no existe. Establecer inactivo para varias versiones, sin embargo, porque ningún lenguaje de uso de ella. Además, las versiones anteriores de C# permiten algunas conversiones limitadas que estaban contravariante. En concreto, le permiten que los delegados de métodos con tipos de devolución compatibles. Además, los tipos de matriz siempre han sido devueltos de covariante. Estas características existentes son distintas de las nuevas de C# 4.0, que realmente le permiten definir sus propios tipos que son devueltos de covariante y contravariantes en algunas de sus parámetros de tipo.

Distribución dinámica

En las características de interoperabilidad en C# 4.0, comenzando por lo que es quizás el cambio más importante.

C# admite ahora el enlace dinámico. El idioma siempre se ha escrito establecimiento inflexible de tipos y continúa a lo que en la versión 4.0. Microsoft cree que esto hace que C# rápida y fácil de usar y adecuado para todo el trabajo a los programadores de .NET son ponerla. Pero hay veces en que necesita para comunicarse con sistemas no basados en. NET.

Tradicionalmente, se han producido al menos dos enfoques para esto. El primero era simplemente importar el modelo externo directamente .NET como un proxy. Interoperabilidad COM proporciona un ejemplo. Desde el lanzamiento original de .NET Framework, utiliza esta estrategia con una herramienta denominada TLBIMP, que crea nuevos tipos de proxy de .NET que se puede utilizar directamente desde C#.

LINQ para SQL, incluido con C# 3.0, contiene una herramienta denominada SQLMETAL, que importa una base de datos en las clases de proxy de C# para su uso con las consultas. Asimismo, puede encontrar una herramienta que importa las clases de Instrumental de administración de Windows (WMI) para C#. Muchas de las tecnologías permiten escribir C# (a menudo con atributos) y, a continuación, realizar interoperabilidad mediante el código escrito a mano como base para las acciones externas, como, por ejemplo, LINQ para SQL, Windows Communication Foundation (WCF) y la serialización.

El segundo enfoque abandona el sistema de tipos de C# completamente: incrustar cadenas y datos en el código. Esto es lo que hace cada vez que se escribe código que, por ejemplo, se invoca un método de un objeto de JScript, o cuando se incrusta una consulta SQL en la aplicación de ADO.NET. Incluso cuando esté haciendo esto cuando aplace el enlace a utilizando la reflexión, aunque la interoperabilidad en que trata con .NET por sí mismo el tiempo de ejecución.

La palabra clave dinámica en C# es una respuesta para tratar los problemas de estos otros métodos. Let’s empezar con un ejemplo sencillo: reflexión. Normalmente, utilizando requiere una gran cantidad de código de infraestructura del modelo, tales como:

object o = GetObject();
Type t = o.GetType();
object result = t.InvokeMember("MyMethod", 
  BindingFlags.InvokeMethod, null, 
  o, new object[] { });
int i = Convert.ToInt32(result);

Con la palabra clave dinámica, en lugar de llamar a un método MyMethod de algún objeto utilizando la reflexión de este modo, ahora puede indicar al compilador, tratar o como dinámico y retrasar todos los análisis hasta el tiempo de ejecución. Código que hace que el siguiente aspecto:

dynamic o = GetObject();
int i = o.MyMethod();

Funciona y lo lleva a cabo la misma tarea con código que es mucho menos complicado.

El valor de esta reducción, simplificada sintaxis de C# es quizás más claro si examina la clase ScriptObject que admite las operaciones en un objeto de JScript. La clase tiene un método de InvokeMember que tenga más y diferentes parámetros, excepto en Silverlight, que tiene en realidad un método Invoke (tenga en cuenta la diferencia en el nombre) con menos parámetros. Ni de las siguientes son los mismos como lo que tendrá que invocar un método en un objeto de IronPython o IronRuby, o en cualquier número de no - C# puede entrar en contacto con los objetos.

También en los objetos que proceden de los lenguajes dinámicos, encontrará una gran variedad de modelos de datos que son inherentemente dinámico y distintas API compatibles con ellos, como, por ejemplo, DOM de HTML, el DOM de System.XML y el modelo de XLinq para XML. LOS objetos COM a menudo son dinámicos y se pueden beneficiar el retardo en tiempo de análisis de algunos del compilador de ejecución.

En esencia, C# 4.0 ofrece una vista simplificada y coherente de las operaciones dinámicas. Para aprovechar las ventajas de la misma, todo lo que necesita hacer es especificar que un valor dado es dinámico, lo que garantiza que el análisis de todas las operaciones en el valor se retrasará hasta el tiempo de ejecución.

En C# 4.0, dinámico es un tipo integrado y un especial pseudo-keyword significa. Observe, sin embargo, es dinámica es diferente de var. Las variables declaradas con var realmente es necesario un establecimiento inflexible de tipos, pero el programador ha abandonado hasta que el compilador para averiguarlo. Cuando el programador utiliza dinámico, el compilador no sabe qué tipo está en uso, el programador deja a averiguar hasta el tiempo de ejecución.

Dinámico y DLR

La infraestructura que admite estas operaciones dinámicas en tiempo de ejecución se denomina el tiempo de ejecución de lenguaje dinámico (DLR). Esta nueva biblioteca de .NET Framework 4 se ejecuta en CLR, al igual que cualquier otra biblioteca administrada. Es responsable de cada operación dinámico entre el idioma que ha iniciado, y el objeto que se produzca en de intermediación. Si un funcionamiento dinámico no está controlado por el objeto que se produzca en, un componente en tiempo de ejecución del compilador de C# controla el enlace. Un diagrama de arquitectura simplificada y incompleta se parece a esto de figura 1.

image: The DLR Runs on Top of the CLR

Figura 1 de la ejecución de DLR en la parte superior de CLR

Lo interesante de un funcionamiento dinámico, como, por ejemplo, una llamada al método dinámico, es que el objeto de destinatario tiene la oportunidad de insertar a sí mismo en el enlace en tiempo de ejecución y por tanto, puede determinar completamente la semántica de cualquier operación dinámica dada. Por ejemplo, observe el siguiente código:

dynamic d = new MyDynamicObject();
d.Bar("Baz", 3, d);

Si se ha definido la MyDynamicObject tal como se muestra a continuación, a continuación, se puede imaginar lo que ocurre:

class MyDynamicObject : DynamicObject {
  public override bool TryInvokeMember(
    InvokeMemberBinder binder, 
    object[] args, out object result) {

    Console.WriteLine("Method: {0}", binder.Name);
    foreach (var arg in args) {
      Console.WriteLine("Argument: {0}", arg);
    }

    result = args[0];
    return true;
  }
}

De hecho, se imprime el código:

Method: Bar
Argument: Baz
Argument: 3
Argument: MyDynamicObject

Mediante la declaración de d es de tipo dinámico, el código que utiliza la instancia MyDynamicObject eficazmente opte por fuera de la comprobación de las operaciones d participa en tiempo de compilación. Uso de forma dinámica “ I Don ’t saber qué tipo se trata de ser, por lo que me Don ’t sabe qué métodos o propiedades que existen en este momento. Compilador, por favor, permita que todo ello a través y, a continuación, averiguarlo si realmente dispone de un objeto en tiempo de ejecución. Por lo tanto, la llamada a barra compila, aunque el compilador no sabe lo que significa. A continuación, en tiempo de ejecución, el propio objeto se le pregunta qué hacer con esta llamada a barra. Eso es lo que TryInvokeMember sabe cómo gestionar.

Ahora, supongamos que en lugar de un MyDynamicObject, se utiliza un objeto de Python:

dynamic d = GetPythonObject();
d.bar("Baz", 3, d);

Si el objeto es el archivo que se enumeran a continuación, a continuación, el código también es válido, y el resultado es prácticamente la misma:

def bar(*args):
  print "Method:", bar.__name__
  for x in args:
    print "Argument:", x

En realidad, para cada uso de un valor dinámico, el compilador genera una gran cantidad de código que inicializa y se utiliza un CallSite de DLR. Ese CallSite contiene toda la información necesitan para enlazar en tiempo de ejecución, incluidos elementos como el nombre del método, datos adicionales, como, por ejemplo, si se realiza la operación de colocar en un contexto checked e información acerca de los argumentos y sus tipos.

Este código, si tuviera que mantenerlo, sería que cada bit tan horrible como, el código de la reflexión mostrado anteriormente, el código ScriptObject o cadenas que contienen consultas XML. Que es el punto de la función dinámica en C#, Don tiene que escribir el código de esta manera.

Cuando se utiliza la palabra clave dinámica, el código puede ser bastante la forma en que desee: al igual que una invocación de método sencillo, una llamada a un indizador, operador, por ejemplo, +, una conversión de tipos o incluso compuestos, como += o ++. Puede incluso utilizar valores dinámicos en los Estados, por ejemplo, if(d) y foreach(var x in d). También se admite evaluación "cortocircuitada", con código como, por ejemplo, d & & ShortCircuited o d?? ShortCircuited.

El valor de la necesidad de proporcionar una infraestructura común para este tipo de operaciones de DLR es que ya no tiene que tratar con una API diferente para cada modelo dinámico para el código basado en, hay sólo una única API. Y ni siquiera es necesario utilizarlo. El compilador de C# puede utilizarlo y que debe dar más tiempo para escribir el código que desee, el código de infraestructura menos tendrá que mantener significa mayor productividad para usted.

El lenguaje C# proporciona no hay métodos abreviados para definir objetos dinámicos. Dinámicos en C# es consume y el uso de objetos dinámicos. Tenga en cuenta lo siguiente:

dynamic list = GetDynamicList();
dynamic index1 = GetIndex1();
dynamic index2 = GetIndex2();
string s = list[++index1, index2 + 10].Foo();

Este código se compila y contiene muchas de las operaciones dinámicas. En primer lugar, hay el pre-increment dinámico en index1, a continuación, agregue de la dinámica con índice2. A continuación, se llama a get del indizador dinámico en la lista. El producto de estas operaciones se llama al miembro de Foo. Por último, el resultado total de la expresión se convierte en una cadena y se almacena en s. Es cinco operaciones dinámicas en una sola línea, cada uno de ellos se enviará en tiempo de ejecución.

El tipo de tiempo de compilación de cada operación dinámico es dinámico y por lo tanto el tipo de “ dynamicness ” de flujos de cálculo para el cálculo. Incluso si no se habían incluido expresiones dinámicas varias veces, aún habría un número de operaciones dinámicas. Todavía hay cinco en esta línea:

string s = nonDynamicList[++index1, index2 + 10].Foo();

Debido a que los resultados de las dos expresiones de índice son dinámicos, también es el propio índice. Y dado que el resultado del índice es dinámico, por lo tanto, la llamada a Foo. A continuación, se enfrentan con convierte un valor dinámico en una cadena. Esto sucede de forma dinámica, por supuesto, ya que el objeto se puede convertir a uno dinámico que desea realizar algún cálculo especial en el caso de una solicitud de conversión.

Observe que en los ejemplos anteriores que C# admite las conversiones implícitas de cualquier expresión dinámico a cualquier tipo. La conversión a cadena al final es implícita y no requirió una operación de conversión explícita. De forma similar, cualquier tipo se puede convertir en dinámicos implícitamente.

En este sentido, dinámico es un lote como objeto y las similitudes Don detener no existe. Cuando el compilador emite el ensamblado y las necesidades de la emisión de la variable dinámica, lo hace mediante el objeto de tipo y, a continuación, marcarlo especialmente. En cierto sentido, dinámico es el tipo de alias de objeto, pero agrega el comportamiento adicional de la resolución de forma dinámica las operaciones cuando lo utiliza.

Esto se puede ver si se intenta realizar la conversión entre tipos genéricos que difieren sólo en dinámicos y el objeto; estas conversiones siempre funcionará, ya que en tiempo de ejecución, una instancia de la lista <dynamic> es realmente una instancia de la lista <object>:

List<dynamic> ld = new List<object>();

También puede ver la similitud entre dinámico y si intenta reemplazar un método que se declara con un parámetro de objeto de objetos:

class C {
  public override bool Equals(dynamic obj) { 
    /* ... */ 
  }
}

Aunque se resuelve como un objeto representativo del ensamblado, quiero pensar dinámico como un tipo real, ya que actúa como recordatorio de que se pueden hacer más cosas con lo que puede hacer con cualquier otro tipo. Puede utilizar como un argumento de tipo o, por ejemplo, como un valor devuelto. Por ejemplo, esta definición de función le permitirá usar el resultado de la llamada de función de forma dinámica sin tener que colocar su valor devuelto de una variable dinámica:

public dynamic GetDynamicThing() { 
  /* ... */ }

Hay muchos más detalles acerca de la forma en que se tratan y se distribuye dinámicos, pero se Don necesita saber para utilizar la función. La idea fundamental es que puede escribir código que es similar a C#, y si alguna parte del código que escribe es dinámico, el compilador dejarla tal cual hasta el tiempo de ejecución.

Me gustaría tratar un tema final sobre dinámicos: error. Debido a que el compilador no puede comprobar si lo dinámico que está utilizando tiene realmente el método llamado Foo, no puede dar un error. Por supuesto, esto no significa que la llamada a Foo funcionará en tiempo de ejecución. También puede funcionar, pero hay una gran cantidad de objetos que Don tiene un método denominado Foo. Cuando se produce un error en la expresión de enlace en tiempo de ejecución, el enlazador convierte su intento de las mejores para ofrecerle una excepción que es más o menos exactamente lo que el compilador se ha dicho si no se habían utilizado dinámico comenzar.

Observe el código siguiente:

try 
{
  dynamic d = "this is a string";
  d.Foo();
}
catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException e)
{
  Console.WriteLine(e.Message);
}

Aquí hay una cadena y cadenas, claramente, no tienen un método denominado Foo. Cuando se ejecuta la línea que llama a Foo, se producirá un error en el enlace y obtendrá un RuntimeBinderException. Esto es lo que se imprime en el programa anterior:

'string' does not contain a definition for 'Foo'

Que es exactamente el error, como programador de C#, esperar.

Argumentos con nombre y parámetros opcionales

En otra incorporación a C#, los métodos admiten ahora parámetros opcionales con los valores predeterminados, de modo que cuando se llama a este método se pueden omitir los parámetros. Esto se puede ver en acción en esta clase Car:

class Car {
  public void Accelerate(
    double speed, int? gear = null, 
    bool inReverse = false) { 

    /* ... */ 
  }
}

Se puede llamar al método de este modo:

Car myCar = new Car();
myCar.Accelerate(55);

Esto tiene exactamente el mismo efecto que:

myCar.Accelerate(55, null, false);

Es el mismo debido a que el compilador inserta todos los valores predeterminados que se omiten.

C# 4.0 también le permiten llamar a métodos mediante la especificación de algunos argumentos por nombre. De esta forma, puede pasar un argumento a un parámetro opcional sin tener que también pasar argumentos para todos los parámetros que vienen antes de él.

Suponga que desea llamar a acelerar para ir a la inversa, pero no desea especificar el parámetro de engranaje. Bien, puede hacer esto:

myCar.Accelerate(55, inReverse: true);

Se trata de una nueva sintaxis de C# 4.0, y es lo mismo que si hubiera escrito:

myCar.Accelerate(55, null, true);

De hecho, o no en el método que va a llamar son opcionales, puede utilizar los nombres al pasar argumentos. Por ejemplo, estas dos llamadas están permitidas y idénticas entre sí:

Console.WriteLine(format: "{0:f}", arg0: 6.02214179e23);
Console.WriteLine(arg0: 6.02214179e23, format: "{0:f}");

Si está llamando a un método que toma una larga lista de parámetros, incluso puede utilizar nombres como una especie de documentación en el código para ayudarle a recordar qué parámetro es que.

En la superficie, argumentos opcionales y los parámetros con nombre no se ven al igual que las características de interoperabilidad. Se pueden utilizar sin alguna vez incluso pensando en interoperabilidad. Sin embargo, la motivación para estas funciones procede de la API de Office. Considere, por ejemplo, la programación de Word y algo tan simple como el método SaveAs en la interfaz de documento. Este método tiene parámetros de 16, que son opcionales. Con las versiones anteriores de C#, si desea llamar a este método tiene que escribir código que tiene este aspecto:

Document d = new Document();
object filename = "Foo.docx";
object missing = Type.Missing;
d.SaveAs(ref filename, 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);

Ahora, puede escribirlo siguiente:

Document d = new Document();
d.SaveAs(FileName: "Foo.docx");

Diría que es una mejora para cualquiera que trabaje con las API similar al siguiente. Y mejorar las vidas de programadores que necesitan escribir programas de Office fue sin duda un factor que motivan a para agregar denominado argumentos y parámetros opcionales para el idioma.

Ahora, cuando escribe una biblioteca de .NET y considerando la posibilidad de agregar los métodos con parámetros opcionales, se plantea una elección. Puede agregar los parámetros opcionales, o puede hacer lo han hecho durante años los programadores de C#: presente las sobrecargas. En el ejemplo Car.Accelerate, la decisión de estos última puede conllevar para producir un tipo que tiene este aspecto:

class Car {
  public void Accelerate(uint speed) { 
    Accelerate(speed, null, false); 
  }
  public void Accelerate(uint speed, int? gear) { 
    Accelerate(speed, gear, false); 
  }
  public void Accelerate(uint speed, int? gear, 
    bool inReverse) { 
    /* ... */ 
  }
}

El modelo que mejor se adapte a la biblioteca que se va a escribir la selección depende de usted. Dado que C# no tiene parámetros opcionales hasta ahora, .NET Framework (incluidos el 4 de .NET Framework) tiende a utilizar las sobrecargas. Si decide combinar sobrecargas con parámetros opcionales, la resolución de sobrecarga de C# tiene reglas de desempate claras para determinar que sobrecargar para llamar a bajo ninguna circunstancia dada.

Propiedades indizadas

Sólo al escribir código con una API de interoperabilidad COM, se admiten algunas características del lenguaje más pequeños de C# 4.0. La interoperabilidad de Word en la ilustración anterior es un ejemplo.

Código de C# siempre ha tenido la noción de un indizador que se pueden agregar a una clase con eficacia sobrecargar el operador [] en las instancias de esa clase. En este sentido de indizador también se denomina un indizador predeterminado, ya que no se le asigna un nombre y una llamada no requiere ningún nombre. Algunas API de COM también tienen indizadores, que no sean la predeterminada, lo que quiere decir que puede no puede llamar eficazmente a ellos simplemente con [], debe especificar un nombre. Como alternativa, se puede considerar una propiedad indizada como una propiedad que tiene algunos argumentos adicionales.

C# 4.0 es compatible con las propiedades indizadas en los tipos de interoperabilidad COM. No puede definir tipos de C#, que dispone de las propiedades indizadas, pero se pueden utilizar siempre que esté realizando etc. COM de tipo. Para obtener un ejemplo del aspecto de código de C# que lo hace, tenga en cuenta la propiedad Range en una hoja de cálculo de Excel:

using Microsoft.Office.Interop.Excel;

class Program {
  static void Main(string[] args) {
    Application excel = new Application();
    excel.Visible = true;

    Worksheet ws = 
      excel.Workbooks.Add().Worksheets["Sheet1"];
    // Range is an indexed property
    ws.Range["A1", "C3"].Value = 123; 
    System.Console.ReadLine();
    excel.Quit();
  }
}

En este ejemplo, el intervalo [“ A1 ”, “ C3 ”] no es una propiedad denominada Range devuelto por una cosa que se puede indizar. Es una llamada a un descriptor de acceso de rango que pasa A1 y C3 con él. Y aunque no es posible que son el valor como una propiedad indizada, también es uno. Todos sus argumentos son opcionales, y porque es una propiedad indizada, se omite especificándolos no en absoluto. Antes de que el idioma compatible de las propiedades indizadas, que se ha escrito la llamada como la siguiente:

ws.get_Range("A1", "C3").Value2 = 123;

En este caso, el valor2 es una propiedad que se ha agregado simplemente porque la propiedad indizada no funcionaría valores anteriores a la 4.0 de C#.

Si se omite la palabra clave de referencia en los sitios de llamada de COM

Algunas API de COM se escribieron con muchos parámetros que se pasa por referencia, incluso cuando la implementación no grabar en ellos. En el conjunto de programas de Office, Word destaca como un ejemplo, su API COM de todo ello.

Al que se enfrentan con dicha biblioteca y tiene que pasar argumentos por referencia, ya no se puede pasar cualquier expresión que no es un campo o variable local, y es un gran dolor de cabeza. En el ejemplo SaveAs de Word, puede ver esto en acción, era necesario declarar una variable local denominada nombre de archivo y una variable local denominada falta para llamar al método SaveAs, ya que los parámetros deben pasarse por referencia.

Document d = new Document();
object filename = "Foo.docx";
object missing = Type.Missing;
d.SaveAs(ref filename, ref missing, // ...

Puede que haya observado en el nuevo código de C# que sigue, ya no esté declarado una variable local para el nombre de archivo:

d.SaveAs(FileName: "Foo.docx");

Esto es posible causa de la nueva característica de referencia para la interoperabilidad COM de omitir. Ahora, cuando se llama a un método de interoperatividad COM, se pueden pasar uno de los argumentos por valor, en lugar de por referencia. Si lo hace, el compilador se crea a una variable local temporal en su nombre y pasarlo locales por referencia por usted si es necesario. Por supuesto, no podrá ver el efecto de la llamada al método si el método Muta el argumento: si desea que, pasar el argumento ref.

Esto puede hacerse código que utiliza las API como este muy limpiador.

Incrustación de objetos de tipos de interoperabilidad COM

Se trata de una característica del compilador de C# de una característica del lenguaje C#, pero ahora se puede utilizar un ensamblado de interoperabilidad COM sin tener que estar presente en tiempo de ejecución del ensamblado. El objetivo es reducir la carga de la implementación de ensamblados de interoperabilidad COM con la aplicación.

Cuando la interoperabilidad COM se introdujo en la versión original de .NET Framework, se creó la noción de un ensamblado de interoperabilidad primario (PIA). Se trataba de un intento de resolver el problema de uso compartido de los objetos COM entre los componentes. Si tiene distintos ensamblados de interoperabilidad que definen una hoja de cálculo de Excel, no podrá compartir estas hojas de cálculo entre los componentes, porque serían los distintos tipos de .NET. El PIA corrige esto existentes de una sola vez, todos los clientes utilizan, y los tipos de .NET siempre coinciden.

Aunque una idea de bien en papel, en la práctica de implementación de que un PIA resulta para ser un dolor de cabeza, porque sólo hay una y varias aplicaciones podría tratar de instalar o desinstalar. Cuestiones son complicadas porque los ensamblados de interoperabilidad primarios con frecuencia son grandes, Office no implementa con las instalaciones predeterminadas de Office y, a los usuarios pueden pasar por alto este sistema de ensamblaje única fácilmente sólo tiene que utilizar TLBIMP para crear su propio ensamblado de interoperabilidad.

Por lo tanto, a continuación, en un intento para corregir esta situación, han pasado dos cosas:

  • El tiempo de ejecución se le ha asignado la inteligencia para tratar a dos estructuralmente COM interoperabilidad tipos idénticos que comparten las mismas características de identificación (nombre, GUID y así sucesivamente) como si fueran realmente el mismo tipo. NET.
  • El compilador de C# aprovecha las ventajas de esto simplemente reproduciendo los tipos en su propio ensamblado de interoperabilidad de cuando se compila, eliminando la necesidad de que el ensamblado de interoperabilidad que existen en tiempo de ejecución.

Se debe omitir algunos detalles por cuestiones de espacio, pero incluso sin conocer los detalles, se trata de otra función, como dinámicos, puede utilizar sin problemas. Para indicar al compilador para incrustar los tipos de interoperabilidad para el en Visual Studio, establezca la propiedad de tipos de interoperabilidad de incrustar en la referencia a true.

Debido a que trata el método preferido para hacer referencia a ensamblados COM espera encontrar en el equipo de C#, Visual Studio se establecerá esta propiedad en True de forma predeterminada para cualquier nueva referencia de interoperabilidad a un proyecto de C#. Si utiliza el compilador de línea de comandos (csc.exe) para generar el código, a continuación, para incrustar la interoperabilidad tipos que se debe hacer referencia al ensamblado de interoperabilidad en cuestión con la /L cambie en lugar / r.

Cada una de las características que he tratado en este artículo no puede propio generar discusión mucho más, y merecen de los temas de todos los artículos de su propia. He omitido o glossed a lo largo de muchos detalles, pero espero que esto sirve como un buen punto de partida para la exploración de C# 4.0 y encontrar tiempo para investigar y asegúrese de utilizar estas características. Y si lo hace, esperamos que disfrute de las ventajas de productividad y la legibilidad del programa que se han diseñado para ofrecerle.

Chris Burrows es un desarrollador de Microsoft en el equipo de compilador de C#. Implementado dinámico en el compilador de C# y con el desarrollo de Visual Studio para nueve años.

Gracias al siguiente experto técnico para este artículo: Eric Lippert