Compartir por


Cambiar reglas de compatibilidad

A lo largo de su historial, .NET ha intentado mantener un alto nivel de compatibilidad de la versión a la versión y entre implementaciones de .NET. Aunque .NET 5 (y .NET Core) y versiones posteriores se pueden considerar como una nueva tecnología en comparación con .NET Framework, dos factores principales limitan la capacidad de esta implementación de .NET para diferir de .NET Framework:

  • Un gran número de desarrolladores originalment han desarrollado o siguen desarrollando aplicaciones de .NET Framework. Esperan un comportamiento coherente en las implementaciones de .NET.
  • .NET proyectos de biblioteca estándar permiten a los desarrolladores crear bibliotecas destinadas a API comunes compartidas por .NET Framework y .NET 5 (y .NET Core) y versiones posteriores. Los desarrolladores esperan que una biblioteca usada en una aplicación de .NET se comporte de forma idéntica a la misma biblioteca que se usa en una aplicación de .NET Framework.

Junto con la compatibilidad entre implementaciones de .NET, los desarrolladores esperan un alto nivel de compatibilidad entre versiones de una implementación determinada de .NET. En concreto, el código escrito para una versión anterior de .NET Core debe ejecutarse sin problemas en .NET 5 o una versión posterior. De hecho, muchos desarrolladores esperan que las nuevas API que se encuentran en las versiones recién publicadas de .NET también sean compatibles con las versiones preliminares en las que se introdujeron esas API.

En este artículo se describen los cambios que afectan a la compatibilidad y a la forma en que el equipo de .NET evalúa cada tipo de cambio. Comprender cómo el equipo de .NET aborda los posibles cambios importantes es especialmente útil para los desarrolladores que abren pull requests que modifican el comportamiento de las API existentes en .NET.

En las secciones siguientes se describen las categorías de cambios realizados en .NET API y su impacto en la compatibilidad de aplicaciones. Los cambios se permiten (✔️), no se permiten (❌) o requieren juicio y una evaluación de cómo de predecible, obvio y coherente fue el comportamiento anterior (❓).

Nota:

  • Además de servir como guía sobre cómo se evalúan los cambios en las bibliotecas de .NET, los desarrolladores de bibliotecas también pueden usar estos criterios para evaluar los cambios en sus bibliotecas destinadas a varias implementaciones y versiones de .NET.
  • Para obtener información sobre las categorías de compatibilidad, por ejemplo, compatibilidad con versiones anteriores y posteriores, vea Cómo los cambios de código pueden afectar a la compatibilidad.

Modificaciones en el contrato público

Los cambios en esta categoría modifican el área expuesta pública de un tipo. La mayoría de los cambios de esta categoría no se permiten, ya que infringen la compatibilidad con versiones anteriores (la capacidad de una aplicación desarrollada con una versión anterior de una API para ejecutarse sin volver a compilarla en una versión posterior).

Tipos

  • ✔️ PERMITIDO: quitar una implementación de interfaz de un tipo cuando una interfaz ya está implementada por un tipo base

  • REQUIERE CRITERIO: Agregar una nueva implementación de interfaz a un tipo

    Se trata de un cambio aceptable porque no afecta negativamente a los clientes existentes. Los cambios en el tipo deben funcionar dentro de los límites de los cambios aceptables definidos aquí para que la nueva implementación siga siendo aceptable. Es necesario tener precaución extrema al agregar interfaces que afectan directamente a la capacidad de un diseñador o serializador para generar código o datos que no se pueden consumir de nivel descendente. Un ejemplo es la ISerializable interfaz .

  • REQUIERE SENTENCIA: Presentación de una nueva clase base

    Un tipo se puede introducir en una jerarquía entre dos tipos existentes si no introduce nuevos miembros abstractos ni cambia la semántica o el comportamiento de los tipos existentes. Por ejemplo, en .NET Framework 2.0, la clase DbConnection se convirtió en una nueva clase base para SqlConnection, que anteriormente se había derivado directamente de Component.

  • ✔️ PERMITIDO: Mover un tipo de un ensamblado a otro

    El ensamblado anterior debe marcarse con el TypeForwardedToAttribute que apunta al nuevo ensamblado.

  • ✔️ PERMITIDO: Cambiar un tipo struct a un tipo readonly struct

    No se permite cambiar un readonly struct tipo a un struct tipo.

  • ✔️ ALLOWED: adición de la palabra clave sealed o abstract a un tipo cuando no hay constructores accesibles (públicos o protegidos)

  • ✔️ PERMITIDO: expandir la visibilidad de un tipo

  • NO PERMITIDO: Cambiar el espacio de nombres o el nombre de un tipo

  • NO PERMITIDO: Cambio de nombre o eliminación de un tipo público

    Esto interrumpe todo el código que utiliza el tipo cuyo nombre se ha cambiado o quitado.

    Nota:

    En raras ocasiones, .NET puede quitar una API pública. Para obtener más información, consulte eliminación de API en .NET. Para obtener información sobre la directiva de soporte técnico de .NET, consulte .NET Directiva de soporte técnico.

  • NO PERMITIDO: Cambiar el tipo subyacente de una enumeración

    Se trata de un cambio importante en tiempo de compilación y de comportamiento, así como de un cambio importante binario que puede hacer que los argumentos de atributos no se puedan analizar.

  • NO PERMITIDO: Sellado de un tipo que anteriormente no estaba sellado

  • NO PERMITIDO: Agregar una interfaz al conjunto de tipos base de una interfaz

    Si una interfaz implementa una interfaz que previamente no implementaba, todos los tipos que implementaron la versión original de la interfaz se rompen.

  • REQUIERE SENTENCIA: Quitar una clase del conjunto de clases base o una interfaz del conjunto de interfaces implementadas

    Hay una excepción a la regla para la eliminación de la interfaz: puede agregar la implementación de una interfaz que deriva de la interfaz eliminada. Por ejemplo, puede eliminar IDisposable si el tipo o la interfaz ahora implementa IComponent, el cual implementa IDisposable.

  • NO PERMITIDO: Cambio de un readonly struct tipo a un tipo de estructura

    Sin embargo, se permite el cambio de un struct tipo a un readonly struct tipo.

  • NO PERMITIDO: Cambio de un tipo de estructura a un ref struct tipo y viceversa

  • NO PERMITIDO: Reducción de la visibilidad de un tipo

    Sin embargo, se permite aumentar la visibilidad de un tipo.

Miembros

  • ✔️ PERMITIDO: Ampliar la visibilidad de un miembro que no es virtual

  • ✔️ PERMITIDO: Adición de un miembro de tipo abstract a un tipo público que no tiene ningún constructor accesible (público o protegido) o el tipo sealed

    Sin embargo, no se permite agregar un miembro abstracto a un tipo que tenga constructores accesibles (públicos o protegidos) y que no sea sealed.

  • ✔️ ALLOWED: restricción de la visibilidad de un miembro protegido cuando el tipo no tiene constructores accesibles (públicos o protegidos) o el tipo está sellado.

  • ✔️ PERMITIDO: Desplazamiento de un miembro a una clase superior en la jerarquía que el tipo del que fue eliminado

  • ✔️ PERMITIDO: Adición o eliminación de una invalidación

    La introducción de una invalidación puede hacer que los consumidores anteriores omitan la invalidación cuando llamen a la base.

  • ✔️ ALLOWED: agregar un constructor a una clase, junto con un constructor sin parámetros si la clase anteriormente no tenía constructores.

    Sin embargo, no se permite agregar un constructor a una clase que antes no tenía constructores sin agregar el constructor sin parámetros.

  • ✔️ PERMITIDO: cambiar un miembro de abstract a virtual

  • ✔️ PERMITIDO: Cambio de un valor devuelto ref readonly a un ref (excepto para los métodos o interfaces virtuales)

  • ✔️ PERMITIDO: Quitar readonly de un campo, a menos que el tipo estático del campo sea un tipo de valor mutable.

  • ✔️ PERMITIDO: Llamada a un nuevo evento que no se ha definido anteriormente

  • REQUIERE SENTENCIA: Agregar un nuevo campo de instancia a un tipo

    Este cambio afecta a la serialización.

  • NO PERMITIDO: Cambiar el nombre o quitar un miembro o parámetro público

    Esto afecta todo el código que utiliza el miembro renombrado o eliminado, o el parámetro.

    Esto incluye el cambio de nombre o eliminación de un captador o establecedor de una propiedad, así como el cambio de nombre o eliminación de los miembros de la enumeración.

  • REQUIERE CRITERIO: Agregar un miembro a una interfaz

    Aunque es un cambio importante en el sentido de que eleva la versión mínima de .NET a .NET Core 3.0 (C# 8.0), que es cuando se introdujeron miembros de interfaz default (DIMs), se permite agregar un miembro estático, no abstracto y no virtual a una interfaz.

    Si proporciona una implementación, agregar un nuevo miembro a una interfaz existente no producirá necesariamente errores de compilación en ensamblados posteriores. Sin embargo, no todos los lenguajes admiten DIMs. Además, en algunos escenarios, el entorno de ejecución no puede decidir qué miembro de interfaz predeterminado invocar. A partir de C# 13, ref struct los tipos pueden implementar interfaces, pero no se pueden boxear ni convertir en un tipo de interfaz. Por lo tanto, un ref struct tipo debe proporcionar una implementación explícita para cada miembro de interfaz de instancia; no puede usar la implementación predeterminada proporcionada por la interfaz. Agregar un miembro de instancia predeterminado a una interfaz que es implementada por ref struct requiere que ref struct añada una implementación correspondiente, lo que constituye un cambio importante en el origen. Por estos motivos, use el criterio al agregar un miembro a una interfaz existente.

    Nota:

    Si la interfaz se implementa mediante tipos ref struct (posible en C# 13 y versiones posteriores), agregar cualquier miembro de instancia predeterminado a la interfaz es un cambio de ruptura para esos llamadores. ref struct debe proporcionar una implementación explícita del nuevo miembro; no se puede revertir a la implementación predeterminada.

  • NO PERMITIDO: Cambiar el valor de una constante pública o un miembro de enumeración

  • NO PERMITIDO: Cambiar el tipo de una propiedad, un campo, un parámetro o un valor devuelto

  • NO PERMITIDO: Agregar, quitar o cambiar el orden de los parámetros

  • NO PERMITIDO: agregar o quitar la palabra clave in, out o ref de un parámetro

  • ✔️ ALLOWED: cambio de un ref parámetro a ref readonly

    Cambiar un parámetro de ref a ref readonly es compatible con el origen para los sitios de llamadas existentes que pasan argumentos con el ref modificador: esas llamadas continúan compilando sin ningún cambio. A diferencia de cambiar ref a in, un parámetro ref readonly no permite silenciosamente a los llamadores pasar rvalues (no variables); el compilador emite una advertencia si el argumento no es una variable. Los sitios de llamada existentes ref siguen siendo válidos.

  • NO PERMITIDO: Cambiar un in parámetro a ref readonly

    Las llamadas a sitios que pasan in argumentos sin el modificador in (que el compilador permite para parámetros in) recibirán una advertencia cuando el parámetro cambie a ref readonly, ya que ref readonly requiere que el argumento se pase por referencia. Los autores de llamadas que tratan las advertencias como errores experimentarán un cambio importante en el origen.

  • NO PERMITIDO: Cambio de nombre de un parámetro (incluido el cambio de mayúsculas y minúsculas)

    Esto se considera disruptivo por dos motivos:

  • NO PERMITIDO: Cambiar de un valor de retorno ref a un valor de retorno ref readonly

  • ❌️ NO PERMITIDO: Cambiar de un valor devuelto ref readonly a un valor devuelto ref en un método virtual o una interfaz

  • NO PERMITIDO: Adición o eliminación del tipo abstract de un miembro

  • NO PERMITIDO: Eliminación de la palabra clave virtual de un miembro

  • NO PERMITIDO: Adición de la palabra clave virtual a un miembro

    Aunque esto a menudo no es un cambio importante porque el compilador de C# tiende a emitir instrucciones de lenguaje intermedio de callvirt (IL) para llamar a métodos que no son virtuales (callvirt realiza una comprobación nula, mientras que una llamada normal no), este comportamiento no es invariable por varias razones:

    • C# no es el único lenguaje que .NET tiene como destino.
    • El compilador de C# intenta cada vez más optimizar callvirt a una llamada normal cada vez que el método de destino no es virtual y probablemente no es null (como un método al que se accede a través del operador de propagación ?. NULL).

    Convertir un método en virtual significa que el código del consumidor a menudo acabaría llamándolo no virtual.

  • NO PERMITIDO: Conversión de un miembro virtual en tipo abstract

    Un miembro virtual proporciona una implementación de método que se puede invalidar mediante una clase derivada. Un miembro abstracto no proporciona ninguna implementación y se debe invalidar.

  • NO PERMITIDO: Agregar la palabra clave sealed a un miembro de interfaz

    Agregar sealed a un miembro de interfaz predeterminado hará que este no sea virtual, impidiendo que se invoque la implementación de un tipo derivado para ese miembro.

  • NO PERMITIDO: agregar un miembro abstracto a un tipo público que tenga constructores accesibles (públicos o protegidos) y que no esté sellado

  • NO PERMITIDO: Adición o eliminación de la palabra clave static de un miembro

  • NO PERMITIDO: agregar una sobrecarga que impida una sobrecarga existente y defina un comportamiento diferente.

    Esto interrumpe a los clientes existentes que se enlazaron a la sobrecarga anterior. Por ejemplo, si una clase tiene una versión única de un método que acepta un UInt32, un consumidor existente se enlazará correctamente a esa sobrecarga al pasar un valor Int32. Sin embargo, si agrega una sobrecarga que acepte un Int32, al volver a compilar o utilizar la característica de enlace en tiempo de ejecución, el compilador se enlaza ahora a la nueva sobrecarga. Si hay resultados de comportamiento diferentes, esto puede ser un cambio importante.

  • REQUIERE SENTENCIA: Agregar OverloadResolutionPriorityAttribute a una sobrecarga existente o cambiar su valor de prioridad

    La OverloadResolutionPriorityAttribute afecta a la resolución de sobrecargas a nivel de origen: los llamantes que se recompilan podrían resolver en una sobrecarga diferente a la anterior. El uso previsto es agregar el atributo a una nueva y mejor sobrecarga para que el compilador la prefiera sobre las existentes. Agregarlo a una sobrecarga existente o cambiar el valor de prioridad en una sobrecarga que ya tiene atributos puede provocar un cambio disruptivo en el código fuente, ya que los compiladores que vuelvan a compilar el código podrían alterar el comportamiento.

  • ✔️ PERMITIDO: Adición de la anti-constraint allows ref struct como restricción a un parámetro de tipo genérico

    Agregar allows ref struct amplía los tipos que se pueden usar como argumentos de tipo al permitir tipos ref struct. Los autores de llamadas existentes que usan argumentos de tipo no-ref struct no se ven afectados. El método o tipo genérico debe seguir las reglas de seguridad ref para todas las instancias de ese parámetro de tipo.

  • NO PERMITIDO: eliminar la allows ref struct anti-restricción de un parámetro de tipo genérico

    Al quitar allows ref struct, se restringen los tipos que los llamantes pueden usar como argumentos de tipo. Cualquier llamador que pase un ref struct como argumento de tipo ya no podrá compilarse.

  • NO PERMITIDO: agregar un constructor a una clase que anteriormente no tenía ningún constructor sin agregar el constructor sin parámetros

  • ❌️ NO PERMITIDO: Agregar readonly a un campo

  • NO PERMITIDO: Reducción de la visibilidad de un miembro

    Esto incluye reducir la visibilidad de un miembro protegido cuando existen constructores accesibles (public o protected) y el tipo no está sellado. Si no es así, se permite reducir la visibilidad de un miembro protegido.

    Se permite aumentar la visibilidad de un miembro.

  • NO PERMITIDO: Cambiar el tipo de un miembro

    No se puede modificar el valor devuelto de un método o el tipo de una propiedad o campo. Por ejemplo, la firma de un método que devuelve un Object no se puede cambiar para devolver un String, o viceversa.

  • NO PERMITIDO: Agregar un campo de instancia a una estructura que no tiene campos no públicos

    Si un struct solo tiene campos públicos o no tiene campos en absoluto, los autores de llamadas pueden declarar variables locales de ese tipo de estructura sin llamar al constructor de la estructura o inicializar primero el local en default(T), siempre y cuando todos los campos públicos se establezcan en la estructura antes de su primer uso. Agregar cualquier nuevo campo (público o no público) a tal estructura representa un cambio fundamental en la fuente para los usuarios, ya que el compilador requerirá que se inicialicen los campos adicionales ahora.

    Además, agregar cualquier campo nuevo (público o no público) a una estructura sin campos o solo con campos públicos es un cambio importante binario en los autores de llamadas que han aplicado [SkipLocalsInit] a su código. Dado que el compilador no era consciente de estos campos en tiempo de compilación, podía emitir IL que no inicializa completamente la estructura, lo que provocaba que la estructura se creara a partir de datos de pila no inicializados.

    Si un struct tiene campos no públicos, el compilador ya aplica la inicialización a través del constructor o default(T)y la adición de nuevos campos de instancia no es un cambio importante.

  • NO PERMITIDO: Desencadenamiento de un evento existente nunca antes desencadenado

Cambios de comportamiento

Ensamblajes

  • ✔️ PERMITIDO: Hacer que un ensamblaje sea portátil cuando todavía se admiten las mismas plataformas

  • NO PERMITIDO: Cambiar el nombre de un ensamblado

  • NO PERMITIDO: Cambio de la clave pública de un ensamblado

Propiedades, campos, parámetros y valores devueltos

  • ✔️ ALLOWED: cambio del valor de una propiedad, un campo, un valor devuelto o un parámetro out a un tipo más derivado

    Por ejemplo, un método que devuelve un tipo de Object puede devolver una String instancia. (Sin embargo, la firma del método no puede cambiar).

  • ✔️ PERMITIDO: Aumento del intervalo de valores aceptados para una propiedad o parámetro si el miembro no es virtual

    Aunque el rango de valores que se pueden pasar al método o que el miembro puede devolver puede expandirse, el tipo de parámetro o miembro no puede cambiar. Por ejemplo, mientras que los valores pasados a un método pueden expandirse de 0 a 124 a 0-255, el tipo de parámetro no puede cambiar de Byte a Int32.

  • NO PERMITIDO: aumentar el intervalo de valores aceptados para una propiedad o parámetro si el miembro es virtual

    Este cambio interrumpe los miembros invalidados existentes, que no funcionarán correctamente para la gama extendida de valores.

  • NO PERMITIDO: Disminuir el intervalo de valores aceptados para una propiedad o parámetro

  • NO PERMITIDO: aumentar el intervalo de valores devueltos para una propiedad, un campo, un valor devuelto o un parámetro out

  • PROHIBIDO: cambiar los valores devueltos para una propiedad, un campo, el valor devuelto de un método o un parámetro out

  • NO PERMITIDO: Cambio del valor predeterminado de una propiedad, un campo o un parámetro

    Cambiar o quitar un valor predeterminado de parámetro no es una interrupción binaria. Eliminar el valor predeterminado de un parámetro es una ruptura del código fuente, y cambiar el valor predeterminado de un parámetro podría dar lugar a una alteración del comportamiento después de la recompilación.

    Por este motivo, quitar los valores predeterminados del parámetro es aceptable en el caso específico de "mover" esos valores predeterminados a una nueva sobrecarga de método para eliminar la ambigüedad. Por ejemplo, considere un método MyMethod(int a = 1)existente. Si introduce una sobrecarga de MyMethod con dos parámetros opcionales a y b, puede conservar la compatibilidad moviendo el valor predeterminado de a a la nueva sobrecarga. Ahora las dos sobrecargas son MyMethod(int a) y MyMethod(int a = 1, int b = 2). Este patrón permite a MyMethod() compilar.

  • NO PERMITIDO: Cambio de la precisión de un valor devuelto numérico

  • REQUIERE EVALUACIÓN: Un cambio en el análisis de la entrada y el inicio de nuevas excepciones (incluso si el comportamiento de análisis no está especificado en la documentación)

  • NO PERMITIDO: Agregar o quitar tipos de casos de una union declaración

    Agregar o quitar un tipo de caso de un union tipo resulta en una ruptura binaria y una ruptura de código fuente.

    Las pruebas de coincidencia de patrones ya no son exhaustivas después de agregar un tipo de caso. El compilador marca expresiones de coincidencia de patrones como no exhaustivas. En tiempo de ejecución, los valores inesperados provocan excepciones en tiempo de ejecución. Al quitar un tipo de caso, se quita la declaración de constructor para ese tipo de caso.

Excepciones

  • ✔️ PERMITIDO: lanzar una excepción más derivada que una excepción existente

    Dado que la nueva excepción es una subclase de una excepción existente, el código de control de excepciones anterior continúa controlando la excepción. Por ejemplo, en .NET Framework 4, los métodos de creación y recuperación de culturas comenzaron a lanzar una CultureNotFoundException en lugar de una ArgumentException si no se encontró la cultura. Dado que CultureNotFoundException se deriva de ArgumentException, se trata de un cambio aceptable.

  • ✔️ PERMITIDO: Inicio de una excepción más específica que NotSupportedException, NotImplementedException, NullReferenceException

  • ✔️ PERMITIDO: Inicio de una excepción que se considera irrecuperable

    Las excepciones irrecuperables no deben capturarse, sino que deben tratarse por un controlador general de alto nivel. Por lo tanto, no se espera que los usuarios tengan código que capture estas excepciones explícitas. Las excepciones irrecuperables son:

  • ✔️ PERMITIDO: Lanzar una nueva excepción en una nueva trayectoria de código

    La excepción solo se debe aplicar a una nueva ruta de acceso de código que se ejecuta con nuevos valores de parámetro o estado y que no se puede ejecutar mediante código existente que tenga como destino la versión anterior.

  • ✔️ ALLOWED: eliminación de una excepción para habilitar un comportamiento más sólido o nuevos escenarios

    Por ejemplo, un método Divide que anteriormente solo trataba valores positivos e iniciaba un ArgumentOutOfRangeException de lo contrario, puede cambiarse para admitir tanto valores negativos como positivos sin iniciar una excepción.

  • ✔️ ALLOWED: Cambio del texto de un mensaje de error

    Los desarrolladores no deben confiar en el texto de los mensajes de error, que también cambian en función de la referencia cultural del usuario.

  • NO PERMITIDO: Lanzar una excepción en cualquier otro caso no enumerado anteriormente

  • NO PERMITIDO: Quitar una excepción en cualquier otro caso no enumerado anteriormente

Atributos

  • ✔️ PERMITIDO: Cambiar el valor de un atributo que no es observable

  • NO PERMITIDO: cambio del valor de un atributo que es observable

  • REQUIERE SENTENCIA: Quitar un atributo

    En la mayoría de los casos, quitar un atributo (como NonSerializedAttribute) es un cambio importante.

Compatibilidad con plataformas

  • ✔️ PERMITIDO: Admisión de una operación en una plataforma que antes no era posible

  • NO PERMITIDO: No admitir o requerir ahora un Service Pack específico para una operación que estaba admitida en una plataforma

Cambios de implementación internos

  • REQUIERE EVALUACIÓN: Cambio del área expuesta de un tipo interno

    Estos cambios se permiten generalmente, aunque interrumpen la reflexión privada. En algunos casos, cuando las bibliotecas populares de terceros o un gran número de desarrolladores dependen de las API internas, es posible que no se permitan estos cambios.

  • REQUIERE EVALUACIÓN: Cambio de la implementación interna de un miembro

    Estos cambios suelen permitirse, aunque interrumpen la reflexión privada. En algunos casos, cuando el código del cliente depende con frecuencia de la reflexión privada o de dónde el cambio introduce efectos secundarios no deseados, es posible que estos cambios no se permitan.

  • ✔️ PERMITIDO: Mejora del rendimiento de una operación

    La capacidad de modificar el rendimiento de una operación es esencial, pero estos cambios pueden interrumpir el código que depende de la velocidad actual de una operación. Esto es especialmente cierto en el código que depende del tiempo de las operaciones asincrónicas. El cambio de rendimiento no debe tener ningún efecto en otro comportamiento de la API en cuestión; De lo contrario, el cambio se interrumpirá.

  • ✔️ PERMITIDO: Indirectamente (y a menudo adversamente) cambiando el rendimiento de una operación

    Si el cambio en cuestión no está clasificado como importante por algún otro motivo, esto es aceptable. A menudo, es necesario realizar acciones que incluyan operaciones adicionales o que agreguen nuevas funcionalidades. Esto casi siempre afectará al rendimiento, pero puede ser esencial para que la API en cuestión funcione según lo previsto.

  • NO PERMITIDO: cambio de una API sincrónica a asincrónica (y viceversa)

Cambios en el código

  • ✔️ PERMITIDO: Se permite la adición de parámetros a un parámetro

  • NO PERMITIDO: Cambio de una estructura a una clase y viceversa

  • NO PERMITIDO: Adición de la instrucción checked a un bloque de código

    Este cambio puede provocar que el código que previamente se ejecutaba arroje un OverflowException, lo cual no es aceptable.

  • NO PERMITIDO: Quitar parámetros de un parámetro

  • NO PERMITIDO: Cambio del tipo de colección de un params parámetro

    A partir de C# 13, los parámetros de params admiten tipos de colección que no son matrices, incluyendo Span<T>, ReadOnlySpan<T>, tipos struct o de clase que implementan IEnumerable<T> con un constructor accesible sin parámetros y un método de instancia Add, así como tipos de interfaz específicos, tales como IList<T>. Cambiar el tipo de colección de un parámetro existente params (por ejemplo, de params T[] a params ReadOnlySpan<T>) cambia la firma IL del método y es un cambio rupturista binario. Los llamadores compilados con la versión anterior deben ser recompilados.

  • ✔️ ALLOWED: convertir un método de extensión en la sintaxis de miembro del bloque de extensión

    A partir de C# 14, puede declarar miembros de extensión mediante bloques extension, además de la sintaxis anterior de parámetros this. Ambas formas generan IL idéntico, por lo que los llamantes no pueden distinguir entre ellos. La conversión de métodos de extensión existentes a la nueva sintaxis de bloque de extensión es binaria y compatible con el origen.

  • NO PERMITIDO: Cambio del orden en el que se desencadenan los eventos

    Los desarrolladores pueden esperar razonablemente que los eventos se activen en el mismo orden y el código de desarrollador con frecuencia depende del orden en el que se desencadenan los eventos.

  • NO PERMITIDO: Eliminación del inicio de un evento en una acción determinada

  • NO PERMITIDO: Cambio del número de veces que se llaman los eventos dados

  • NO PERMITIDO: Agregar a FlagsAttribute un tipo de enumeración

Consulte también