ref readonly
parâmetros
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 reunião de design de linguagem (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/6010
Resumo
Permitir o modificador ref readonly
no local de declaração de parâmetro e alterar as regras do local de chamada da seguinte maneira:
Anotação de ponto de chamada | Parâmetro ref |
parámetro ref readonly |
parâmetro in |
out parâmetro |
---|---|---|---|---|
ref |
Permitido | Permitido | Aviso | Erro |
in |
Erro | Permitido | Permitido | Erro |
out |
Erro | Erro | Erro | Permitido |
Sem anotação | Erro | Aviso | Permitido | Erro |
Observe que há uma alteração nas regras existentes: o parâmetro in
com a anotação ref
gera um aviso ao invés de um erro.
Altere as regras de valor do argumento da seguinte maneira:
Tipo de valor | Parâmetro ref |
ref readonly parâmetro |
in parâmetro |
parâmetro out |
---|---|---|---|---|
rvalue | Erro | Aviso | Permitido | Erro |
lvalue | Permitido | Permitido | Permitido | Permitido |
Onde lvalue significa uma variável (ou seja, um valor com uma localização; não precisa ser gravável/atribuível) e rvalue significa qualquer tipo de valor.
Motivação
O C# 7.2 introduziu parâmetros in
como uma maneira de passar referências somente leitura.
in
Parâmetros permitem ambos os lvalues e rvalues e podem ser usados sem qualquer anotação no local da chamada.
No entanto, as APIs que capturam ou retornam referências de seus parâmetros gostariam de não permitir rvalues e também impor alguma indicação no site de chamada de que uma referência está sendo capturada.
Os parâmetros ref readonly
são ideais nesses casos, pois avisam se usados com *rvalues* ou sem qualquer anotação no ponto de chamada.
Além disso, há APIs que precisam apenas de referências de leitura única, mas usam
-
ref
parâmetros desde que foram introduzidos antes dein
se tornar disponível e mudar parain
seria uma alteração que quebra a compatibilidade a nível de código-fonte e binário, por exemplo,QueryInterface
, ou -
in
parâmetros para aceitar referências somente leitura, mesmo que passar rvalues para eles não faça muito sentido, por exemplo,ReadOnlySpan<T>..ctor(in T value)
ou -
ref
parâmetros para impedir rvalues mesmo que não alterem a referência passada, por exemplo,Unsafe.IsNullRef
.
Essas APIs poderiam migrar para parâmetros ref readonly
sem interromper os usuários.
Para obter detalhes sobre compatibilidade binária, consulte a proposta sobre a codificação de metadados .
Especificamente, alterando
-
ref
→ref readonly
seria apenas uma mudança de quebra binária para métodos virtuais, -
ref
→in
também seria uma mudança que quebra a binariedade para métodos virtuais, mas não quebraria o código-fonte (porque as regras mudam para avisar apenas sobre argumentosref
passados para parâmetrosin
), -
in
→ref readonly
não seria uma alteração que quebra a compatibilidade (mas nenhuma anotação de local de chamada ou rvalue resultaria em um aviso),- Observe que isso seria uma alteração de quebra de fonte para usuários que usam versões mais antigas do compilador (pois interpretam
ref readonly
parâmetros como parâmetrosref
, não permitindoin
ou nenhuma anotação no site de chamada) e novas versões do compilador comLangVersion <= 11
(para consistência com versões mais antigas do compilador, será emitido um erro de queref readonly
parâmetros não são suportados, a menos que os argumentos correspondentes sejam passados com o modificadorref
).
- Observe que isso seria uma alteração de quebra de fonte para usuários que usam versões mais antigas do compilador (pois interpretam
Na direção oposta, mudando
-
ref readonly
→ref
seria potencialmente uma alteração que quebra a compatibilidade com o código-fonte (a menos que apenas a anotação de local de chamadaref
fosse usada e apenas referências de leitura apenas fossem usadas como argumentos) e uma alteração de quebra binária para métodos virtuais, -
ref readonly
→in
não seria uma alteração disruptiva (mas a anotação de ponto de chamadaref
resultaria em um aviso).
Observe que as regras descritas acima se aplicam a assinaturas de método, mas não a assinaturas delegadas.
Por exemplo, alterar ref
para in
em uma assinatura delegada pode ser uma alteração de quebra de origem (se um usuário estiver atribuindo um método com ref
parâmetro a esse tipo de delegado, isso se tornará um erro após a alteração da API).
Desenho detalhado
Em geral, as regras para os parâmetros ref readonly
são as mesmas que as especificadas para os parâmetros in
na sua proposta , exceto quando explicitamente alteradas nesta proposta.
Declarações de parâmetros
Não são necessárias alterações gramaticais.
O modificador ref readonly
será permitido para parâmetros.
Além dos métodos normais, ref readonly
serão permitidos para parâmetros indexadores (como in
mas ao contrário ref
), mas não permitidos para parâmetros do operador (como ref
mas ao contrário in
).
Os valores padrão dos parâmetros serão permitidos para os parâmetros ref readonly
com um aviso, pois são equivalentes a passar rvalues.
Isso permite que os autores da API alterem os parâmetros in
com valores padrão para os parâmetros ref readonly
sem introduzir uma alteração que quebre a origem.
Verificações de tipo de valor
Observe que, embora o modificador de argumento ref
seja permitido para os parâmetros ref readonly
, nada muda relativamente às verificações do tipo de valor, ou seja,
-
ref
só pode ser usado com valores atribuíveis; - Para passar referências só de leitura, é preciso usar o modificador de argumento
in
; - Para passar valores r, é preciso não usar nenhum modificador (o que resulta em um aviso para
ref readonly
parâmetros, conforme descrito em o resumo desta proposta).
Resolução de sobrecarga
A resolução de sobrecarga permitirá misturar ref
/ref readonly
/in
/sem anotações de local de chamada e modificadores de parâmetros, conforme indicado pela tabela em o resumo desta proposta, ou seja, todos os permitidos e de aviso de casos serão considerados como possíveis candidatos durante a resolução de sobrecarga.
Especificamente, há uma mudança no comportamento existente em que os métodos com in
parâmetro corresponderão às chamadas com o argumento correspondente marcado como ref
—essa alteração será limitada no LangVersion.
No entanto, o aviso para fornecer um argumento sem um modificador de local de chamada para um parâmetro ref readonly
será suprimido se o parâmetro for
- o recetor numa invocação do método de extensão,
- usado implicitamente como parte do inicializador de coleção personalizado ou manipulador de cadeia de caracteres interpolada.
As sobrecargas por valor serão preferidas às sobrecargas ref readonly
no caso de não haver um modificador de argumento (os parâmetrosin
têm o mesmo comportamento).
Conversões de método
Da mesma forma, para fins de função anônima [§10.7] e grupo de método [§10.8] conversões, esses modificadores são considerados compatíveis (mas qualquer conversão permitida entre modificadores diferentes resulta em um aviso):
-
ref readonly
parâmetro do método de destino pode corresponder ain
ouref
parâmetro do delegado, - O parâmetro
in
do método de destino pode corresponder ao parâmetroref readonly
ou, dependendo da LangVersion, ao parâmetroref
do delegado. - Nota: O parâmetro
ref
do método de destino não é permitido para corresponder ao parâmetroin
nem ao parâmetroref readonly
do delegado.
Por exemplo:
DIn dIn = (ref int p) => { }; // error: cannot match `ref` to `in`
DRef dRef = (in int p) => { }; // warning: mismatch between `in` and `ref`
DRR dRR = (ref int p) => { }; // error: cannot match `ref` to `ref readonly`
dRR = (in int p) => { }; // warning: mismatch between `in` and `ref readonly`
dIn = (ref readonly int p) => { }; // warning: mismatch between `ref readonly` and `in`
dRef = (ref readonly int p) => { }; // warning: mismatch between `ref readonly` and `ref`
delegate void DIn(in int p);
delegate void DRef(ref int p);
delegate void DRR(ref readonly int p);
Observe que não há nenhuma alteração no comportamento das conversões de ponteiro da função . Como lembrete, conversões implícitas de ponteiros de funções não são permitidas se houver uma incompatibilidade entre modificadores do tipo de referência, e conversões explícitas são sempre permitidas sem avisos.
Correspondência de assinaturas
Os membros declarados num único tipo não podem diferir na assinatura apenas por ref
/out
/in
/ref readonly
.
Para outros fins de correspondência de assinatura (por exemplo, ocultar ou substituir), ref readonly
pode ser trocado pelo modificador in
, mas isso resulta num aviso no local da declaração [§7.6].
Isso não se aplica ao alinhar a declaração partial
com a sua implementação e ao alinhar a assinatura do interceptor com a assinatura intercetada.
Observe que não há nenhuma alteração na sobreposição para os pares modificadores ref
/in
e ref readonly
/ref
, eles não podem ser trocados, porque as assinaturas não são compatíveis binariamente.
Por uma questão de coerência, o mesmo se aplica a outros fins de correspondência de assinaturas (por exemplo, ocultação).
Codificação de metadados
Como lembrete,
- Os parâmetros
ref
são emitidos como tipos por referência "byref" simples (T&
em IL). -
in
parâmetros são comoref
mais eles são anotados comSystem.Runtime.CompilerServices.IsReadOnlyAttribute
. Em C# 7.3 e posteriores, eles também são emitidos com[in]
e, se forem virtuais, commodreq(System.Runtime.InteropServices.InAttribute)
.
ref readonly
parâmetros serão emitidos como [in] T&
, além de anotados com o seguinte atributo:
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
public sealed class RequiresLocationAttribute : Attribute
{
}
}
Além disso, se virtuais, eles serão emitidos com modreq(System.Runtime.InteropServices.InAttribute)
para garantir a compatibilidade binária com os parâmetros in
.
Observe que, ao contrário in
parâmetros, nenhum [IsReadOnly]
será emitido para ref readonly
parâmetros para evitar o aumento do tamanho dos metadados e também para fazer com que versões mais antigas do compilador interpretem ref readonly
parâmetros como parâmetros ref
(e, portanto, não será uma mudança de quebra de fonte, mesmo entre diferentes versões ref
→ ref readonly
do compilador).
O RequiresLocationAttribute
será identificado pelo nome qualificado do namespace e gerado pelo compilador, caso ainda não esteja incluído na compilação.
Especificar o atributo na origem será um erro se ele for aplicado a um parâmetro, da mesma forma que ParamArrayAttribute
.
Ponteiros de função
Em ponteiros de função, os parâmetros in
são associados a modreq(System.Runtime.InteropServices.InAttribute)
(veja a proposta de ponteiros de função ).
Os ref readonly
parâmetros serão emitidos sem aquele modreq
, mas com o modopt(System.Runtime.CompilerServices.RequiresLocationAttribute)
.
Versões mais antigas do compilador ignorarão o modopt
e, portanto, interpretarão ref readonly
parâmetros como parâmetros ref
(consistente com o comportamento mais antigo do compilador para métodos normais com parâmetros ref readonly
conforme descrito acima) e novas versões do compilador cientes do modopt
o usarão para reconhecer parâmetros ref readonly
para emitir avisos durante conversões e invocações.
Para manter a consistência com versões mais antigas do compilador, as novas versões do compilador com LangVersion <= 11
reportarão erros indicando que os parâmetros ref readonly
não são suportados, a menos que os argumentos correspondentes sejam passados com o modificador ref
.
Observe que é uma quebra binária para alterar modificadores em assinaturas de ponteiro de função se eles fizerem parte de APIs públicas, portanto, será uma quebra binária ao alterar ref
ou in
para ref readonly
.
No entanto, uma quebra de origem só ocorrerá para chamadores com LangVersion <= 11
ao alterar in
→ ref readonly
(se invocar o ponteiro com o modificador do local de chamada in
), de forma consistente com os métodos normais.
Mudanças significativas
O relaxamento de incompatibilidade de ref
/in
na resolução de sobrecarga introduz uma alteração que causa ruptura no comportamento, como demonstrado no exemplo a seguir:
class C
{
string M(in int i) => "C";
static void Main()
{
int i = 5;
System.Console.Write(new C().M(ref i));
}
}
static class E
{
public static string M(this C c, ref int i) => "E";
}
Em C# 11, a chamada liga-se a E.M
e, portanto, "E"
é impressa.
No C# 12, C.M
é permitido vincular (com um aviso) e nenhum escopo de extensão é pesquisado, pois temos um candidato aplicável, portanto, "C"
é impresso.
Há também uma alteração que quebra a origem devido ao mesmo motivo.
O exemplo abaixo imprime "1"
em C# 11, mas falha ao compilar com um erro de ambiguidade em C# 12:
var i = 5;
System.Console.Write(C.M(null, ref i));
interface I1 { }
interface I2 { }
static class C
{
public static string M(I1 o, ref int x) => "1";
public static string M(I2 o, in int x) => "2";
}
Os exemplos acima demonstram as interrupções para invocações de método, mas como estas são causadas por alterações na resolução de sobrecarga, elas podem ser acionadas de forma semelhante para conversões de métodos.
Alternativas
Declarações de parâmetros
Os autores da API podem anotar in
parâmetros projetados para aceitar apenas lvalues com um atributo personalizado e fornecer um analisador para sinalizar usos incorretos.
Isso não permitiria que os autores da API alterassem assinaturas de APIs existentes que optaram por usar parâmetros ref
para não permitir rvalues.
Os chamadores dessas APIs ainda precisariam executar trabalho extra para obter um ref
se tivessem acesso apenas a uma variável ref readonly
.
Alterar essas APIs de ref
para [RequiresLocation] in
seria uma alteração que quebra a compatibilidade de origem (e, no caso de métodos virtuais, também uma alteração que quebra a compatibilidade binária).
Em vez de permitir que o modificador ref readonly
, o compilador poderia reconhecer quando um atributo especial (como [RequiresLocation]
) é aplicado a um parâmetro.
Isso foi discutido em LDM 2022-04-25, com a decisão de que isto é um recurso de linguagem, não um analisador, e, portanto, deve assemelhar-se a tal.
Verificações de tipo de valor
Passar lvalues sem modificadores para parâmetros ref readonly
pode ser permitido sem quaisquer avisos, semelhante aos parâmetros byref implícitos do C++.
Isso foi discutido em LDM 2022-05-11, observando que a principal motivação para os parâmetros ref readonly
é que as APIs capturam ou retornam referências destes parâmetros, por isso é bom ter um marcador de algum tipo.
Passar rvalue para um ref readonly
pode ser um erro, não um aviso.
Isso foi inicialmente aceite em LDM 2022-04-25, mas discussões posteriores por e-mail relaxaram isso porque perderíamos a capacidade de alterar APIs existentes sem causar problemas aos utilizadores.
in
pode ser o modificador de callsite "natural" para parâmetros ref readonly
e usar ref
pode resultar em avisos de alerta.
Isso garantiria um estilo de código consistente e tornaria óbvio no local de chamada que a referência é somente leitura (ao contrário de ref
).
Foi inicialmente aceite em LDM 2022-04-25.
No entanto, os avisos podem ser um ponto de atrito para os autores da API passarem de ref
para ref readonly
.
Além disso, in
foi redefinido como ref readonly
+ recursos de conveniência, portanto, isso foi rejeitado em LDM 2022-05-11.
Revisão pendente do LDM
Nenhuma das seguintes opções foi implementada no C# 12. Continuam a ser propostas potenciais.
Declarações de parâmetros
A ordenação inversa dos modificadores (readonly ref
em vez de ref readonly
) poderia ser permitida.
Isso seria inconsistente com o modo como os retornos e campos de readonly ref
se comportam (a ordenação inversa não é permitida ou significa algo diferente, respectivamente) e poderia entrar em conflito com parâmetros apenas de leitura se implementados no futuro.
Os valores padrão dos parâmetros podem resultar em erro para os parâmetros ref readonly
.
Verificações de tipo de valor
Erros podem ser gerados em vez de avisos ao passar rvalues para parâmetros ref readonly
ou quando há incompatibilidade entre anotações de callsite e modificadores de parâmetros.
Da mesma forma, um modreq
especial poderia ser usado em vez de um atributo para garantir que os parâmetros ref readonly
sejam distintos dos parâmetros in
no nível binário.
Isso forneceria garantias mais fortes, então seria bom para novas APIs, mas impediria a adoção em APIs de tempo de execução existentes que não podem introduzir alterações de quebra.
As verificações do tipo de valor podem ser flexibilizadas para permitir a passagem de referências de leitura apenas via ref
em parâmetros in
/ref readonly
.
Isso seria semelhante a como as atribuições ref e os retornos ref funcionam hoje — eles também permitem passar referências como somente leitura por meio do modificador ref
na expressão de origem.
No entanto, o ref
geralmente está perto do local onde o alvo é declarado como ref readonly
, então é claro que estamos passando uma referência como somente leitura, ao contrário de invocações cujos modificadores de argumento e parâmetro geralmente estão distantes.
Além disso, eles permitem que apenas o modificador ref
, ao contrário dos argumentos que permitem também in
, portanto, in
e ref
se tornariam intercambiáveis para argumentos, ou in
se tornariam praticamente obsoletos se os usuários quisessem tornar seu código consistente (eles provavelmente usariam ref
em todos os lugares, já que é o único modificador permitido para atribuições ref e retornos ref).
Resolução de sobrecarga
Resolução de sobrecarga, substituição e conversão podem impedir a intercambiabilidade de modificadores de ref readonly
e in
.
A alteração na resolução de sobrecarga para parâmetros in
existentes poderia ser tomada incondicionalmente (não considerando LangVersion), mas isso seria uma alteração incompatível.
Invocar um método de extensão com ref readonly
recetor poderia resultar em aviso "O argumento 1 deve ser passado com ref
ou in
palavra-chave", como aconteceria para invocações sem extensão sem modificadores de callsite (o usuário poderia corrigir esse aviso transformando a invocação do método de extensão em invocação de método estático).
A mesma advertência pode ser emitida ao usar um inicializador de coleção personalizado ou um manipulador de cadeia de caracteres interpolada com o parâmetro ref readonly
, mesmo que o utilizador não o possa contornar.
ref readonly
sobrecargas podem ser preferíveis em vez de sobrecargas por valor quando não há um modificador no local de chamada ou pode ocorrer um erro de ambiguidade.
Conversões de Método
Poderíamos permitir que ref
parâmetro do método de destino correspondesse a in
e ref readonly
parâmetro do delegado.
Isso permitiria que os autores da API alterassem, por exemplo, ref
para in
em assinaturas delegadas sem quebrar seus usuários (de forma consistente com o que é permitido para assinaturas de método normais).
No entanto, também resultaria numa violação das garantias readonly
, com apenas um aviso:
class Program
{
static readonly int f = 123;
static void Main()
{
var d = (in int x) => { };
d = (ref int x) => { x = 42; }; // warning: mismatch between `ref` and `in`
d(f); // changes value of `f` even though it is `readonly`!
System.Console.WriteLine(f); // prints 42
}
}
As conversões de ponteiro de função poderiam alertar sobre ref readonly
/ref
/in
incompatibilidade, mas se quiséssemos excluir isso no LangVersion, seria necessário um investimento significativo na implementação, pois hoje as conversões de tipo não precisam de acesso à compilação.
Além disso, mesmo que a incompatibilidade seja atualmente um erro, é fácil para os usuários adicionar um elenco para permitir a incompatibilidade, se quiserem.
Codificação de metadados
Especificar o RequiresLocationAttribute
na origem pode ser permitido, da mesma forma que os atributos In
e Out
.
Pode, alternativamente, tratar-se de um erro quando aplicado em outros contextos além de apenas parâmetros, de forma semelhante ao atributo IsReadOnly
; para preservar mais espaço de design.
Os parâmetros de ref readonly
de ponteiro de função podem ser emitidos com diferentes combinações de modopt
/modreq
(observe que "quebra de fonte" nesta tabela significa para chamadores com LangVersion <= 11
):
Modificadores | Pode ser reconhecido em compilações | Os compiladores antigos vêem-nos como |
ref → ref readonly |
in → ref readonly |
---|---|---|---|---|
modreq(In) modopt(RequiresLocation) |
Sim | in |
binário, quebra de origem | quebra binária |
modreq(In) |
Não | in |
binário, interrupção na origem | Ok |
modreq(RequiresLocation) |
Sim | sem suporte | binário, ruptura no código fonte | binário, quebra de origem |
modopt(RequiresLocation) |
Sim | ref |
quebra binária | binário, quebra de código |
Poderíamos emitir atributos [RequiresLocation]
e [IsReadOnly]
para ref readonly
parâmetros.
Então in
→ ref readonly
não seria uma mudança de quebra mesmo para versões mais antigas do compilador, mas ref
→ ref readonly
se tornaria uma mudança de quebra de fonte para versões mais antigas do compilador (como eles interpretariam ref readonly
como in
, não permitindo modificadores ref
) e novas versões do compilador com LangVersion <= 11
(para consistência).
Poderíamos tornar o comportamento para LangVersion <= 11
diferente do comportamento para versões mais antigas do compilador.
Por exemplo, pode ser um erro sempre que um parâmetro ref readonly
é chamado (mesmo ao usar o modificador ref
no local de chamada), ou pode ser sempre permitido sem erros.
Quebrando mudanças
Esta proposta sugere aceitar uma alteração disruptiva de comportamento porque é pouco provável de ocorrer, é controlada pelo LangVersion, e os utilizadores podem contornar isso chamando o método de extensão explicitamente. Em vez disso, poderíamos mitigá-lo
- desautorizar a incompatibilidade de
ref
/in
(que só impediria a migração parain
para APIs antigas que usavamref
porquein
ainda não estava disponível), - modificar as regras de resolução de sobrecarga para continuar a procurar uma melhor correspondência (determinada pelas regras de melhoria especificadas abaixo) quando houver uma incompatibilidade do tipo ref introduzida nesta proposta,
- ou alternativamente, continuar apenas com o desajuste de
ref
vs.in
, e não com os outros (por valorref readonly
vs.ref
/in
).
- ou alternativamente, continuar apenas com o desajuste de
Regras de melhoria
O exemplo a seguir atualmente resulta em três erros de ambiguidade para as três invocações de M
.
Poderíamos acrescentar novas regras de melhoria para resolver as ambiguidades.
Isso também resolveria a alteração de quebra de fonte descrita anteriormente.
Uma maneira seria fazer com que o exemplo imprimisse 221
(onde ref readonly
parâmetro é correspondido com in
argumento, já que seria um aviso chamá-lo sem modificador, enquanto para in
parâmetro isso é permitido).
interface I1 { }
interface I2 { }
class C
{
static string M(I1 o, in int i) => "1";
static string M(I2 o, ref readonly int i) => "2";
static void Main()
{
int i = 5;
System.Console.Write(M(null, ref i));
System.Console.Write(M(null, in i));
System.Console.Write(M(null, i));
}
}
Novas regras de melhoria poderiam marcar como pior o parâmetro cujo argumento poderia ter sido passado com um modificador de argumento diferente para torná-lo melhor.
Em outras palavras, o usuário deve ser sempre capaz de transformar um parâmetro pior em um parâmetro melhor, alterando seu modificador de argumento correspondente.
Por exemplo, quando um argumento é passado por in
, um parâmetro ref readonly
é preferido sobre um parâmetro in
porque o usuário pode passar o argumento por valor para escolher o parâmetro in
.
Esta regra é apenas uma extensão da regra de preferência por valor/in
que está em vigor hoje (é a última regra de resolução de sobrecarga e toda a sobrecarga é melhor se qualquer um dos seus parâmetros for melhor e nenhum for pior do que o parâmetro correspondente de outra sobrecarga).
argumento | melhor parâmetro | pior parâmetro |
---|---|---|
ref /in |
ref readonly |
in |
ref |
ref |
ref readonly /in |
por valor | por valor/in |
ref readonly |
in |
in |
ref |
Devemos lidar com conversões de método de forma semelhante.
O exemplo a seguir atualmente resulta em dois erros de ambiguidade para as duas atribuições de delegado.
Novas regras de otimização podem preferir um parâmetro de método cujo modificador de refness corresponda ao do parâmetro de delegado de destino, em vez de um que tenha uma incompatibilidade.
Assim, o exemplo a seguir imprimiria 12
.
class C
{
void M(I1 o, ref readonly int x) => System.Console.Write("1");
void M(I2 o, ref int x) => System.Console.Write("2");
void Run()
{
D1 m1 = this.M;
D2 m2 = this.M; // currently ambiguous
var i = 5;
m1(null, in i);
m2(null, ref i);
}
static void Main() => new C().Run();
}
interface I1 { }
interface I2 { }
class X : I1, I2 { }
delegate void D1(X s, ref readonly int x);
delegate void D2(X s, ref int x);
Reuniões de design
- LDM 2022-04-25: recurso aceite
- LDM 2022-05-09: discussão dividida em três partes
-
LDM 2022-05-11: permitida
ref
e sem anotação de callsite para parâmetrosref readonly
C# feature specifications