Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Observação
Este artigo é uma especificação de recurso. A especificação serve como o documento de design para o recurso. Ele inclui mudanças de especificação propostas, juntamente com as informações necessárias durante o design e desenvolvimento do recurso. Estes artigos são publicados até que as alterações de especificações propostas sejam finalizadas e incorporadas na especificação ECMA atual.
Pode haver algumas discrepâncias entre a especificação do recurso e a implementação concluída. Essas diferenças são capturadas nas notas pertinentes da Language Design Meeting (LDM).
Você pode saber mais sobre o processo de adoção de especificações de recursos no padrão de linguagem C# no artigo sobre as especificações .
Questão campeã: https://github.com/dotnet/csharplang/issues/6420
Gramática
A property_declaration gramática (§14.7.1) é atualizada da seguinte forma:
property_declaration
- : attributes? property_modifier* type member_name property_body
+ : attributes? property_modifier* 'partial'? type member_name property_body
;
Observações: Isto é um pouco semelhante à forma como method_header(§15.6.1) e class_declaration(§15.2.1) são especificados. (Observe que a questão #946 propõe relaxar o requisito de ordenação e provavelmente será aplicável a todas as declarações que permitem o modificador partial
. Pretendemos especificar esse relaxamento de ordenação brevemente e implementá-lo na mesma versão em que este recurso for implementado.)
Definição e aplicação das declarações
Quando uma declaração de propriedade inclui um modificador parcial , essa propriedade é considerada uma propriedade parcial . As propriedades parciais só podem ser declaradas como membros de tipos parciais.
Diz-se que uma declaração de de propriedade parcial é uma declaração definidora quando todos os seus acessadores têm corpos de ponto-e-vírgula, e ela não tem o modificador extern
. Caso contrário, trata-se de uma declaração de execução .
partial class C
{
// Defining declaration
public partial string Prop { get; set; }
// Implementing declaration
public partial string Prop { get => field; set => field = value; }
}
Como reservámos a forma sintática com corpos acessadores de ponto-e-vírgula para a declaração definidora, uma propriedade parcial não pode ser implementada automaticamente. Portanto, ajustamos propriedades implementadas automaticamente (§15.7.4) da seguinte forma:
Uma propriedade implementada automaticamente (ou auto-propriedade, para abreviar) é uma propriedade não abstrata, não externa, não parcial, não referenciada, com corpos de acessores que têm apenas ponto e vírgula.
Observações. É útil para o compilador ser capaz de olhar para uma única declaração isoladamente e saber se é uma declaração definidora ou de implementação. Portanto, não queremos permitir propriedades automáticas ao incluir, por exemplo, duas declarações de propriedade partial
idênticas. Não achamos que os casos de uso desse recurso envolvam a implementação da propriedade parcial com uma propriedade automática, mas nos casos em que uma implementação trivial é desejada, achamos que a palavra-chave field
torna as coisas simples o suficiente.
Uma propriedade parcial deve ter uma declaração definidora e uma declaração de implementação.
Observações. Também não achamos útil permitir a divisão da declaração em mais de duas partes, para permitir que diferentes acessadores sejam implementados em locais diferentes, por exemplo. Portanto, limitamo-nos a imitar o esquema estabelecido por métodos parciais.
Somente a declaração definidora de uma propriedade parcial participa da pesquisa, semelhante a como somente a declaração definidora de um método parcial participa da resolução de sobrecarga.
Observações. No compilador, esperaríamos que apenas o símbolo da declaração definidora aparecesse na lista de membros, e o símbolo da parte implementadora pudesse ser acessado através do símbolo definidor. No entanto, alguns recursos, como a análise anulável, podem ver através de à declaração de implementação, a fim de fornecer um comportamento mais ú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.
{
}
}
Uma propriedade parcial não tem permissão para ter o modificador de abstract
.
Uma propriedade parcial não pode implementar explicitamente propriedades de interface.
Mesclagem de atributos
Semelhante aos métodos parciais, os atributos na propriedade resultante são os atributos combinados das partes são concatenados em uma ordem não especificada e as duplicatas não são removidas.
Atributos de informação do chamador
Ajustamos o seguinte idioma a partir do padrão :
É um erro ter o mesmo atributo caller-info num parâmetro tanto na parte de definição como na de implementação de uma declaração de membrodo método parcial
. Somente os atributos caller-info na parte definidora são aplicados, enquanto os atributos caller-info que ocorrem apenas na parte de implementação são ignorados.
- O erro descrito não se enquadra nas definições destes atributos por não conter
AllowMultiple = true
. Usá-los várias vezes, inclusive em declarações parciais, resulta em um erro. - Quando os atributos caller-info são aplicados a um parâmetro na parte de implementação de um método parcial, o compilador Roslyn relata um aviso. Também será emitido um aviso para o mesmo cenário numa propriedade incompleta.
Correspondência de assinaturas
A reunião do LDM de 14 de setembro de 2020 definiu um conjunto de requisitos "rigorosos" para a correspondência de assinaturas de métodos parciais, que foram introduzidos em uma onda de alerta. As propriedades parciais têm requisitos análogos aos métodos parciais para correspondência de assinaturas, tanto quanto possível, exceto que todos os diagnósticos de incompatibilidade são relatados por padrão e não são mantidos atrás de uma onda de aviso.
Os requisitos de correspondência de assinatura incluem:
- As diferenças de tipo e tipo de referência entre declarações de propriedade parciais que são significativas para o tempo de execução resultam em erro durante a compilação.
- Diferenças nos nomes de elementos de tupla em declarações de propriedade parciais resultam num erro durante a compilação; o mesmo que para métodos parciais.
- As declarações de propriedade e suas declarações de acessador devem ter os mesmos modificadores, embora os modificadores possam aparecer em uma ordem diferente.
- Exceção: não se aplica ao modificador
extern
, que só pode figurar numa declaração de execução .
- Exceção: não se aplica ao modificador
- Todas as outras diferenças sintáticas nas assinaturas de declarações parciais de propriedade resultam em um aviso em tempo de compilação, com as seguintes exceções:
- As listas de atributos nas declarações de propriedade parciais ou dentro delas não precisam corresponder. Em vez disso, a mesclagem de atributos em posições correspondentes é feita conforme descrito em Mesclagem de Atributos.
- Diferenças de contexto anuláveis não causam avisos. Em outras palavras, uma diferença em que um dos tipos é anulável-ignorante e o outro tipo é anulável-anotado ou não-anulável-anotado não resulta em nenhum aviso.
- Os valores dos parâmetros padrão não precisam corresponder. É gerado um aviso quando a parte de implementação de um indexador parcial tem valores de parâmetros predefinidos. Isso é semelhante a um aviso existente que ocorre quando a parte de implementação de um método parcial tem valores de parâmetro padrão.
- Um aviso ocorre quando os nomes dos parâmetros diferem entre a definição e a implementação de declarações. Os nomes dos parâmetros da parte de definição são usados nos locais de uso e na emissão.
- As diferenças de anulabilidade que não envolvem anulabilidade implícita resultam em advertências. Ao analisar um corpo de acessador, a assinatura da parte de implementação é usada. A assinatura da peça de definição é usada ao analisar sites de uso e em emissão. Isto é consistente com métodos parciais.
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
}
Comentários da documentação
Queremos que o comportamento dos comentários de documentos sobre propriedades parciais seja consistente com o que enviamos para métodos parciais. Esse comportamento é detalhado em https://github.com/dotnet/csharplang/issues/5193.
É permitido incluir comentários doc sobre a parte de definição ou implementação de uma propriedade parcial. (Observe que os comentários doc não são suportados em acessadores de propriedade.)
Quando os comentários doc estão presentes em apenas uma das partes da propriedade, esses comentários doc são usados normalmente (apresentados através de ISymbol.GetDocumentationCommentXml()
, escritos no arquivo XML da documentação, etc.).
Quando os comentários doc estão presentes em ambas as partes, todos os comentários doc na parte de definição são descartados e apenas os comentários doc na parte de implementação são usados.
Por exemplo, o seguinte 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 { } }
}
Resulta no seguinte arquivo de documentação 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>
Quando os nomes dos parâmetros diferem entre declarações parciais, os elementos <paramref>
usam os nomes dos parâmetros da declaração associada ao comentário da documentação no código-fonte. Por exemplo, um paramref em um comentário doc colocado em uma declaração de implementação refere-se aos símbolos de parâmetro na declaração de implementação usando seus nomes de parâmetro. Isto é consistente com métodos parciais.
/// <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.
}
Resulta no seguinte arquivo de documentação 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>
Isso pode ser confuso, porque a assinatura de metadados usará nomes de parâmetros da parte de definição. Recomenda-se garantir que os nomes dos parâmetros correspondam entre as partes para evitar essa confusão.
Indexadores
De acordo com reunião do LDM em 2 de novembro de 2022,, os indexadores receberão suporte com este recurso.
A gramática dos indexadores é modificada da seguinte forma:
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
;
Os parâmetros do indexador parcial devem corresponder entre as declarações exatamente de acordo com as mesmas regras definidas em Assinaturas correspondentes. A mesclagem de atributos é realizada em parâmetros parciais do indexador.
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;
}
}
Questões em aberto
Outros tipos de membros
Um membro da comunidade abriu uma discussão para solicitar apoio para eventos parciais . Na reunião do LDM, em 2 de novembro de 2022,, decidimos adiar o apoio a eventos, em parte porque, na época, ninguém havia solicitado. Podemos querer revisitar esta questão, uma vez que este pedido já foi apresentado e já passou mais de um ano desde a última vez que o discutimos.
Também poderíamos ir ainda mais longe ao permitir declarações parciais de construtores, operadores, campos e assim por diante, mas não está claro se o ônus do projeto deles é justificado, apenas porque já estamos fazendo propriedades parciais.
C# feature specifications