Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Nota
Este artículo es una especificación de características. La especificación actúa como documento de diseño de la característica. Incluye cambios de especificación propuestos, junto con la información necesaria durante el diseño y el desarrollo de la característica. Estos artículos se publican hasta que se finalizan los cambios de especificación propuestos e se incorporan en la especificación ECMA actual.
Puede haber algunas discrepancias entre la especificación de características y la implementación completada. Esas diferencias se recogen en las notas de la reunión de diseño de lenguaje (LDM) correspondientes.
Puede obtener más información sobre el proceso de adopción de especificaciones de características en el estándar del lenguaje C# en el artículo sobre las especificaciones de .
Problema planteado por el experto: https://github.com/dotnet/csharplang/issues/6420
Gramática
La gramática property_declaration (sección 14.7.1) se actualiza como sigue:
property_declaration
- : attributes? property_modifier* type member_name property_body
+ : attributes? property_modifier* 'partial'? type member_name property_body
;
Comentarios: esto es algo similar a cómo se especifican method_header(§15.6.1) y class_declaration(§15.2.1). (Tenga en cuenta que la Cuestión #946 propone relajar el requisito de orden, y probablemente se aplicaría a todas las declaraciones que permiten el modificador partial
. Tenemos la intención de especificar dicha relajación del orden en un futuro próximo, e implementarla en la misma versión en la que se implemente esta característica).
Definición e implementación de declaraciones
Cuando una declaración de propiedad incluye un modificador parcial , esa propiedad se considera una propiedad parcial . Las propiedades parciales solo se pueden declarar como miembros de tipos parciales.
Se dice que una declaración de propiedad parcial es una declaración de definición cuando todos sus descriptores de acceso tienen cuerpos de punto y coma y carece del modificador extern
. En caso contrario, se trata de una declaración de implementación.
partial class C
{
// Defining declaration
public partial string Prop { get; set; }
// Implementing declaration
public partial string Prop { get => field; set => field = value; }
}
Dado que hemos reservado la forma sintáctica con cuerpos descriptores de acceso de punto y coma para la declaración definitoria, una propiedad parcial no puede implementarse automáticamente. Por lo tanto, ajustamos propiedades implementadas automáticamente (§15.7.4) de la siguiente manera:
Una propiedad implementada automáticamente (o auto-propiedad para abreviar), es una propiedad no abstracta, no-externa, no-parcial, no-ref-valued con cuerpos de acceso de solo punto y coma.
Observaciones. Resulta útil que el compilador pueda examinar una sola declaración de forma aislada y saber si es una declaración de definición o una declaración de implementación. Por lo tanto, no queremos permitir auto-propiedades incluyendo dos declaraciones de propiedades partial
idénticas, por ejemplo. No creemos que los casos de uso de esta característica impliquen la implementación de la propiedad parcial con una propiedad automática, pero en los casos en los que se desea una implementación trivial, creemos que la palabra clave field
hace que las cosas sean lo suficientemente sencillas.
Una propiedad parcial debe tener una declaración definitoria y una declaración de implementación .
Observaciones. Tampoco creemos que es útil permitir la división de la declaración en más de dos partes, para permitir que se implementen descriptores de acceso diferentes en diferentes lugares, por ejemplo. Por lo tanto, simplemente imitamos el esquema establecido por métodos parciales.
Solo la declaración de definición de una propiedad parcial participa en la búsqueda, similar a la forma en que solo la declaración de definición de un método parcial participa en la resolución de sobrecargas.
Observaciones. En el compilador, esperaríamos que solo aparezca el símbolo de la declaración definitoria en la lista de miembros, y se pueda acceder al símbolo de la parte de implementación a través del símbolo definitorio. Sin embargo, algunas características como el análisis nullable podrían ver a través de la declaración de implementación con el fin de proporcionar un comportamiento más útil.
partial class C
{
public partial string Prop { get; set; }
public partial string Prop { get => field; set => field = value; }
public C() // warning CS8618: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
{
}
}
No se permite que una propiedad parcial tenga el modificador abstract
.
Una propiedad parcial no puede implementar explícitamente propiedades de interfaz.
Combinación de atributos
De forma similar a los métodos parciales, en la propiedad resultante los atributos combinados de las partes se concatenan en un orden no especificado, y no se quitan los duplicados.
Atributos de información del autor de la llamada
Ajustamos el siguiente idioma del estándar :
Es un error tener el mismo atributo caller-info en un parámetro tanto de la parte definidora como de la parte implementadora de una declaración parcial
methodmember. Solo se aplican atributos de información del autor de la llamada en el elemento de definición, mientras que los atributos de información del autor de la llamada que se producen solo en la parte de implementación se omiten.
- El error descrito se debe a que las definiciones de estos atributos no tienen
AllowMultiple = true
. El uso de ellos varias veces, incluida en declaraciones parciales, produce un error. - Cuando se aplican atributos de información de llamada a un parámetro en la parte de implementación de un método parcial, el compilador de Roslyn notifica una advertencia. También informará de una advertencia para el mismo escenario en una propiedad parcial.
Firmas coincidentes
En la reunión de LDM del 14 de septiembre de 2020 se definió un conjunto de requisitos "estrictos" para la correspondencia de firmas de métodos parciales, que se introdujeron en una oleada de advertencias. Las propiedades parciales tienen requisitos análogos a los métodos parciales para la correspondencia de firmas en la medida de lo posible, salvo que todos los diagnósticos de falta de correspondencia se notifican por defecto y no se mantienen tras una onda de advertencia.
Entre los requisitos de coincidencia de firmas se incluyen:
- Las diferencias de tipo y clase de referencia entre declaraciones de propiedades parciales que sean significativas para el tiempo de ejecución provocan un error de compilación.
- Las diferencias en los nombres de elementos de tupla dentro de las declaraciones de propiedades parciales provocan un error en tiempo de compilación, al igual que en el caso de los métodos parciales.
- Las declaraciones de propiedad y sus declaraciones de acceso deben tener los mismos modificadores, aunque estos pueden aparecer en un orden diferente.
- Excepción: esto no se aplica al modificador
extern
, que solo puede aparecer en una declaración de implementación .
- Excepción: esto no se aplica al modificador
- Todas las demás diferencias sintácticas en las firmas de declaraciones de propiedades parciales producen una advertencia en tiempo de compilación, con las siguientes excepciones:
- Las listas de atributos en o dentro de las declaraciones de propiedades parciales no necesitan coincidir. En su lugar, se realiza una fusión de atributos en las posiciones correspondientes, según la fusión de atributos.
- Las diferencias de contexto anulables no provocan advertencias. En otras palabras, una diferencia en la que uno de los tipos es nullable-oblivious y el otro tipo es nullable-annotated o not-nullable-annotated no provoca ninguna advertencia.
- Los valores de parámetro predeterminados no necesitan coincidir. Se notifica una advertencia cuando la parte de implementación de un indexador parcial tiene valores de parámetro predeterminados. Esto es similar a una advertencia existente que se produce cuando la parte de implementación de un método parcial tiene valores de parámetro predeterminados.
- Se produce una advertencia cuando los nombres de parámetro difieren en la definición e implementación de declaraciones. Los nombres de los parámetros de la parte de definición se utilizan en los sitios de uso y en emit.
- Las diferencias de nulabilidad que no implican nulabilidad omitosa dan lugar a advertencias. Cuando se analiza el cuerpo de un accessor, se utiliza la firma de la parte de implementación. La firma de la parte de definición se utiliza al analizar los sitios de uso y en emit. Esto es coherente con los métodos parciales.
partial class C1
{
public partial string Prop { get; private set; }
// Error: accessor modifier mismatch in 'set' accessor of 'Prop'
public partial string Prop { get => field; set => field = value; }
}
partial class C2
{
public partial string Prop { get; init; }
// Error: implementation of 'Prop' must have an 'init' accessor to match definition
public partial string Prop { get => field; set => field = value; }
}
partial class C3
{
public partial string Prop { get; }
// Error: implementation of 'Prop' cannot have a 'set' accessor because the definition does not have a 'set' accessor.
public partial string Prop { get => field; set => field = value; }
}
partial class C4
{
public partial string this[string s = "a"] { get; set; }
public partial string this[string s] { get => s; set { } } // ok
public partial string this[int i, string s = "a"] { get; set; }
public partial string this[int i, string s = "a"] { get => s; set { } } // CS1066: The default value specified for parameter 's' will have no effect because it applies to a member that is used in contexts that do not allow optional arguments
}
Comentarios de documentación
Queremos que el comportamiento de los comentarios de documento en las propiedades parciales sea coherente con lo que hemos enviado para los métodos parciales. Ese comportamiento se detalla en https://github.com/dotnet/csharplang/issues/5193.
Se permite incluir comentarios de documento en la parte de definición o implementación de una propiedad parcial. (Ten en cuenta que los doc comments no están soportados en los accessors de propiedades).
Cuando los comentarios de documentación están presentes solo en una de las partes de la propiedad, esos comentarios de documentación se utilizan normalmente (emergen a través de ISymbol.GetDocumentationCommentXml()
, se escriben en el archivo XML de documentación, etc.).
Cuando los comentarios del documento están presentes en ambas partes, se quitan todos los comentarios de documento de la parte de definición y solo se usan los comentarios de documento en la parte de implementación.
Por ejemplo, el siguiente programa:
/// <summary>
/// My type
/// </summary>
partial class C
{
/// <summary>Definition part comment</summary>
/// <returns>Return value comment</returns>
public partial int Prop { get; set; }
/// <summary>Implementation part comment</summary>
public partial int Prop { get => 1; set { } }
}
Da como resultado el siguiente archivo de documentación XML:
<?xml version="1.0"?>
<doc>
<assembly>
<name>ConsoleApp1</name>
</assembly>
<members>
<member name="T:C">
<summary>
My type
</summary>
</member>
<member name="P:C.Prop">
<summary>
Implementation part comment
</summary>
</member>
</members>
</doc>
Cuando los nombres de parámetro difieren entre declaraciones parciales, los elementos <paramref>
usan los nombres de parámetro de la declaración asociada con el comentario de documentación en el código fuente. Por ejemplo, una referencia de parámetro en un comentario de documento ubicado en una declaración de implementación se refiere a los símbolos de los parámetros de dicha declaración utilizando sus nombres. Esto es coherente con los métodos parciales.
/// <summary>
/// My type
/// </summary>
partial class C
{
public partial int this[int x] { get; set; }
/// <summary>
/// <paramref name="x"/> // warning CS1734: XML comment on 'C.this[int]' has a paramref tag for 'x', but there is no parameter by that name
/// <paramref name="y"/> // ok. 'Go To Definition' will go to 'int y'.
/// </summary>
public partial int this[int y] { get => 1; set { } } // warning CS9256: Partial property declarations 'int C.this[int x]' and 'int C.this[int y]' have signature differences.
}
Da como resultado el siguiente archivo de documentación XML:
<?xml version="1.0"?>
<doc>
<assembly>
<name>ConsoleApp1</name>
</assembly>
<members>
<member name="T:C">
<summary>
My type
</summary>
</member>
<member name="P:C.Item(System.Int32)">
<summary>
<paramref name="x"/> // warning CS1734: XML comment on 'C.this[int]' has a paramref tag for 'x', but there is no parameter by that name
<paramref name="y"/> // ok. 'Go To Definition' will go to 'int y'.
</summary>
</member>
</members>
</doc>
Esto puede resultar confuso, ya que la firma de metadatos usará nombres de parámetro de la parte de definición. Se recomienda asegurarse de que los nombres de parámetro coincidan entre partes para evitar esta confusión.
Indizadores
Según la reunión de LDM del 2 de noviembre de 2022, los indexadores serán compatibles con esta función.
La gramática de los indexadores queda modificada de la siguiente manera:
indexer_declaration
- : attributes? indexer_modifier* indexer_declarator indexer_body
+ : attributes? indexer_modifier* 'partial'? indexer_declarator indexer_body
- | attributes? indexer_modifier* ref_kind indexer_declarator ref_indexer_body
+ | attributes? indexer_modifier* 'partial'? ref_kind indexer_declarator ref_indexer_body
;
Los parámetros de los indexadores parciales deben coincidir en todas las declaraciones según las mismas reglas que las firmas coincidentes. La fusión de atributos se realiza a través de parámetros de indexador parciales.
partial class C
{
public partial int this[int x] { get; set; }
public partial int this[int x]
{
get => this._store[x];
set => this._store[x] = value;
}
}
// attribute merging
partial class C
{
public partial int this[[Attr1] int x]
{
[Attr2] get;
set;
}
public partial int this[[Attr3] int x]
{
get => this._store[x];
[Attr4] set => this._store[x] = value;
}
// results in a merged member emitted to metadata:
public int this[[Attr1, Attr3] int x]
{
[Attr2] get => this._store[x];
[Attr4] set => this._store[x] = value;
}
}
Problemas abiertos
Otros tipos de miembros
Un miembro de la comunidad abrió un debate para solicitar soporte para eventos parciales. En la reunión de LDM del 2 de noviembre de 2022, decidimos no dar soporte a los eventos, en parte porque nadie lo había solicitado en ese momento. Es posible que deseemos volver a consultar esta pregunta, ya que esta solicitud ya ha llegado, y ha pasado más de un año desde que lo discutimos por última vez.
También podríamos ir más allá y permitir declaraciones parciales de compiladores, operadores, campos, etc., pero no está claro si la carga de diseño de estos está justificada, solo porque ya estamos haciendo propiedades parciales.
C# feature specifications