Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você 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. Ela inclui alterações de especificação propostas, juntamente com as informações necessárias durante o design e o desenvolvimento do recurso. Esses artigos são publicados até que as alterações de especificação propostas sejam finalizadas e incorporadas na especificação ECMA atual.
Pode haver algumas divergências entre a especificação do recurso e a implementação concluída. Essas diferenças são capturadas nas notas LDM (reunião de design de idioma) pertinentes.
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.
Problema do especialista: https://github.com/dotnet/csharplang/issues/9058
Resumo
Permitir que o partial modificador em eventos e construtores separe as partes de declaração e implementação, semelhante a métodos parciais e propriedades/indexadores parciais.
partial class C
{
partial C(int x, string y);
partial event Action<int, string> MyEvent;
}
partial class C
{
partial C(int x, string y) { }
partial event Action<int, string> MyEvent
{
add { }
remove { }
}
}
Motivação
O C# já dá suporte a métodos, propriedades e indexadores parciais. Faltam eventos parciais e construtores.
Eventos parciais seriam úteis para bibliotecas de eventos fracas, onde o usuário poderia escrever definições:
partial class C
{
[WeakEvent]
partial event Action<int, string> MyEvent;
void M()
{
RaiseMyEvent(0, "a");
}
}
E um gerador de fontes fornecido pela biblioteca forneceria implementações:
partial class C
{
private readonly WeakEvent _myEvent;
partial event Action<int, string> MyEvent
{
add { _myEvent.Add(value); }
remove { _myEvent.Remove(value); }
}
protected void RaiseMyEvent(int x, string y)
{
_myEvent.Invoke(x, y);
}
}
Eventos parciais e construtores parciais também seriam úteis para gerar código de interoperabilidade, como no Xamarin , em que o usuário poderia escrever definições parciais de construtor e evento:
partial class AVAudioCompressedBuffer : AVAudioBuffer
{
[Export("initWithFormat:packetCapacity:")]
public partial AVAudioCompressedBuffer(AVAudioFormat format, uint packetCapacity);
[Export("create:")]
public partial event EventHandler Created;
}
E o gerador de origem geraria as associações (para Objective-C neste caso):
partial class AVAudioCompressedBuffer : AVAudioBuffer
{
[BindingImpl(BindingImplOptions.GeneratedCode | BindingImplOptions.Optimizable)]
public partial AVAudioCompressedBuffer(AVAudioFormat format, uint packetCapacity) : base(NSObjectFlag.Empty)
{
// Call Objective-C runtime:
InitializeHandle(
global::ObjCRuntime.NativeHandle_objc_msgSendSuper_NativeHandle_UInt32(
this.SuperHandle,
Selector.GetHandle("initWithFormat:packetCapacity:"),
format.GetNonNullHandle(nameof(format)),
packetCapacity),
"initWithFormat:packetCapacity:");
}
public partial event EventHandler Created
{
add { /* ... */ }
remove { /* ... */ }
}
}
Design detalhado
Geral
A sintaxe da declaração de evento (§15.8.1) é estendida para permitir o modificador partial.
event_declaration
- : attributes? event_modifier* 'event' type variable_declarators ';'
+ : attributes? event_modifier* 'partial'? 'event' type variable_declarators ';'
- | attributes? event_modifier* 'event' type member_name
+ | attributes? event_modifier* 'partial'? 'event' type member_name
'{' event_accessor_declarations '}'
;
A sintaxe da declaração do construtor da instância (§15.11.1) é estendida para permitir o modificador partial:
constructor_declaration
- : attributes? constructor_modifier* constructor_declarator constructor_body
+ : attributes? constructor_modifier* 'partial'? constructor_declarator constructor_body
;
Observe que há uma proposta para permitir o partial modificador em qualquer lugar entre os modificadores, em vez de apenas como o último (também para declarações de método, propriedade e tipo).
Uma declaração de evento com o partial modificador é considerada uma declaração de evento parcial e está associada a um ou mais eventos parciais com os nomes especificados (observe que uma declaração de evento sem acessadores pode definir vários eventos).
Uma declaração de construtor com o partial modificador é considerada uma declaração de construtor parcial e está associada a um construtor parcial com a assinatura especificada.
Uma declaração de evento parcial é considerada uma declaração de implementação quando especifica o event_accessor_declarations ou tem o extern modificador.
Caso contrário, é uma declaração definidora.
Uma declaração de construtor parcial é considerada uma declaração de definição quando tem um corpo de ponto-e-vírgula e não tem o extern modificador.
Caso contrário, é uma declaração de implementação.
partial class C
{
// defining declarations
partial C();
partial C(int x);
partial event Action E, F;
// implementing declarations
partial C() { }
partial C(int x) { }
partial event Action E { add { } remove { } }
partial event Action F { add { } remove { } }
}
Somente a declaração de definição de um membro parcial participa da pesquisa e é considerada nos sites de uso e para a emissão de metadados. (Exceto para comentários sobre documentação, conforme detalhado abaixo.) A assinatura da declaração de implementação é usada para análise anulável dos corpos associados.
Um evento ou construtor parcial:
- Só pode ser declarado como membro de um tipo parcial.
- Deve ter uma declaração de definição e uma declaração de implementação.
- Não é permitido ter o modificador
abstract. - Não é possível implementar explicitamente um membro da interface.
Um evento parcial não é semelhante a um campo (§15.8.2), ou seja:
- Ele não tem nenhum armazenamento de backup ou acessadores gerados pelo compilador.
- Ele só pode ser usado em
+=e-=operações, não como um valor.
Uma declaração de definição de construtor parcial não pode ter um inicializador de construtor (: this() ou : base(); §15.11.2).
Quebra de análise
Permitir o modificador partial em mais contextos é uma mudança radical:
class C
{
partial F() => new partial(); // previously a method, now a constructor
@partial F() => new partial(); // workaround to keep it a method
}
class partial { }
Para simplificar o analisador de linguagem, o partial modificador é aceito em qualquer declaração semelhante a um método (ou seja, funções locais e métodos de script de nível superior), mesmo que não especifiquemos as alterações gramaticais explicitamente acima.
Atributos
Os atributos do evento ou construtor resultante são os atributos combinados das declarações parciais nas posições correspondentes. Os atributos combinados são concatenados em uma ordem não especificada e as duplicatas não são removidas.
O methodattribute_target (§22.3) é ignorado em declarações de evento parciais.
Os atributos de acessor são usados somente a partir de declarações de acessor (que podem estar presentes apenas na declaração de implementação).
Observe que param e returnattribute_targetjá são ignorados em todas as declarações de evento.
Os atributos Caller-info na declaração de implementação são ignorados pelo compilador, conforme especificado pela proposta de propriedades parciais na seção Atributos Caller-info (observe que ele se aplica a todos os membros parciais que incluem eventos parciais e construtores).
Assinaturas
Ambas as declarações de um membro parcial devem ter assinaturas correspondentes, similares às de propriedades parciais:
- As diferenças de tipo e tipo de referência entre declarações parciais que são significativas para o tempo de execução resultam em um erro de tempo de compilação.
- As diferenças nos nomes de elementos de tuplas entre declarações parciais resultam em um erro de tempo de compilação.
- As declarações devem ter os mesmos modificadores, embora os modificadores possam aparecer em uma ordem diferente.
- Exceção: não se aplica ao
externmodificador que só pode figurar na declaração de execução.
- Exceção: não se aplica ao
- Todas as outras diferenças sintacticas nas assinaturas de declarações parciais resultam em um aviso de tempo de compilação, com as seguintes exceções:
- As listas de atributos não precisam corresponder conforme descrito acima.
- Diferenças de contexto anuláveis (como oblivious vs. annotated) não causam avisos.
- Os valores de parâmetro padrão não precisam corresponder, mas um aviso é relatado quando a declaração do construtor de implementação tem valores de parâmetro padrão (porque eles seriam ignorados, pois apenas a declaração de definição participa da pesquisa).
- Um aviso ocorre quando os nomes de parâmetro diferem entre a definição e a implementação de declarações de construtor.
- Diferenças de nulidade que não envolvem sem reconhecimento de anulável resultam em avisos.
Comentários de documentação
É permitido incluir comentários em documentos sobre a declaração de definição e de execução. Observe que não há suporte para comentários de documentos em acessadores de eventos.
Quando os comentários do documento estão presentes em apenas uma das declarações de um membro parcial, esses comentários do documento são usados normalmente (exibidos por meio das APIs do Roslyn, emitidos para o arquivo XML de documentação).
Quando os comentários do documento estão presentes em ambas as declarações de um membro parcial, todos os comentários do documento na declaração de definição são descartados e somente os comentários do documento na declaração de implementação são usados.
Quando os nomes de parâmetro diferem entre as declarações de um membro parcial, os elementos paramref usam os nomes de parâmetro da declaração que está associada ao comentário da documentação no código-fonte.
Por exemplo, um paramref em um documento colocado em uma declaração de implementação refere-se aos símbolos de parâmetro da declaração de implementação usando seus nomes de parâmetro.
Isso pode ser confuso, pois a assinatura de metadados usará nomes de parâmetro da declaração de definição.
É recomendável garantir que os nomes de parâmetro correspondam às declarações de um membro parcial para evitar essa confusão.
Perguntas abertas
Tipos de membros
Queremos eventos parciais, construtores, operadores, campos? Propomos os dois primeiros tipos de membros, mas qualquer outro subconjunto pode ser considerado.
Construtores primários parciais também podem ser considerados, por exemplo, permitindo que o usuário tenha a mesma lista de parâmetros em várias declarações de tipo parcial.
Locais de atributo
Devemos reconhecer o especificador de destino de [method:] atributo para eventos parciais (ou apenas as declarações de definição)?
Então, os atributos de acessório resultantes seriam a concatenação dos atributos de destino method de ambas as partes da declaração (ou apenas da parte definidora) mais os atributos de autodestino e de destino method dos acessadores da declaração de implementação
A combinação de atributos de diferentes tipos de declaração seria sem precedentes e, de fato, a implementação atual da correspondência de atributos em Roslyn não dá suporte a isso.
Também podemos considerar reconhecer [param:] e [return:], não apenas em eventos parciais, mas em todos os eventos do tipo campo e eventos externos.
Para obter mais detalhes, confira https://github.com/dotnet/roslyn/issues/77254.
C# feature specifications