Parâmetros ref readonly
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 pertinentes da reunião de design de idioma (LDM).
Você pode aprender mais sobre o processo de adoção das especificações de recursos para o padrão de linguagem C# no artigo sobre as especificações .
Problema do especialista: https://github.com/dotnet/csharplang/issues/6010
Resumo
Permite o modificador de declaração no local do parâmetro ref readonly
e altera as regras do ponto de chamada da seguinte maneira:
Anotação do local de chamada | Parâmetro ref |
Parâmetro ref readonly |
Parâmetro in |
Parâmetro out |
---|---|---|---|---|
ref |
Permitido | Permitido | Aviso | Erro |
in |
Erro | Permitido | Permitido | Erro |
out |
Erro | Erro | Erro | Permitido |
Nenhuma anotação | Erro | Aviso | Permitido | Erro |
(Observe que houve uma alteração nas regras existentes: o parâmetro in
com a anotação ref
no local de chamada produz um aviso em vez de um erro.)
Altere as regras de valor do argumento da seguinte maneira:
Tipo de valor | Parâmetro ref |
Parâmetro ref readonly |
Parâmetro in |
Parâmetro out |
---|---|---|---|---|
rvalue | Erro | Aviso | Permitido | Erro |
lvalue | Permitido | Permitido | Permitido | Permitido |
Quando lvalue significa uma variável (ou seja, um valor com um local; 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.
Os parâmetros in
permitem tanto lvalues quanto rvalues e podem ser usados sem nenhuma anotação no local de chamada.
No entanto, as APIs que capturam ou retornam referências de seus parâmetros gostariam de não permitir rvalues e impor alguma indicação no local de chamada de que uma referência está sendo capturada.
Os parâmetros ref readonly
são ideais nesses casos, pois sinalizam quando são usados com rvalues ou sem nenhuma anotação no local de chamada.
Além disso, há APIs que precisam apenas de referências de leitura apenas, mas usam
- parâmetros
ref
desde pois foram introduzidos antes dein
ficar disponível e mudar parain
seria uma mudança que quebra a compatibilidade de origem e binária, por exemplo,QueryInterface
ou - Parâmetros
in
para aceitar referências de somente leitura, mesmo que passar rvalues para elas não faça muito sentido, como, por exemplo,ReadOnlySpan<T>..ctor(in T value)
ou - Parâmetros
ref
para não permitir rvalues mesmo quando não modificam a referência passada, por exemplo,Unsafe.IsNullRef
.
Essas APIs podem migrar para parâmetros ref readonly
sem interromper os usuários.
Para obter detalhes sobre compatibilidade binária, consulte a codificação de metadados proposta .
Especificamente, alterando
ref
→ref readonly
seria uma mudança que quebra a compatibilidade binária apenas para métodos virtuais,ref
→in
também seria uma alteração que quebra a compatibilidade binária para métodos virtuais, mas não uma alteração que quebra a compatibilidade de origem (uma vez que as regras mudam apenas para avisar sobre argumentosref
passados para parâmetrosin
),-
in
→ref readonly
não seria uma alteração significativa (mas nenhuma anotação de chamada ou rvalue resultaria em um aviso),- observe que essa seria uma alteração que quebra a compatibilidade para usuários que usam versões mais antigas do compilador (pois elas interpretam parâmetros
ref readonly
como parâmetrosref
, não permitindoin
ou a ausência de anotação no ponto de chamada) e novas versões do compilador comLangVersion <= 11
(para consistência com versões mais antigas do compilador, um erro será emitido indicando que os parâmetrosref readonly
não são suportados, a menos que os argumentos correspondentes sejam passados com o modificadorref
).
- observe que essa seria uma alteração que quebra a compatibilidade para usuários que usam versões mais antigas do compilador (pois elas interpretam parâmetros
No sentido oposto, alterando
ref readonly
→ref
seria potencialmente uma mudança de quebra de fonte (a menos que apenas a anotação do site de chamadaref
tenha sido usada e apenas referências somente leitura sejam usadas como argumentos), e uma mudança de quebra binária para métodos virtuais.ref readonly
→in
não seria uma alteração significativa (mas a anotação no local de chamada deref
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 de delegado pode ser uma alteração que causa quebra de compatibilidade (se um usuário estiver atribuindo um método com parâmetro ref
a esse tipo de delegado, isso se tornaria um erro após a alteração da API).
Projeto detalhado
Em geral, as regras para os parâmetros de
Declarações de parâmetro
Nenhuma alteração na gramática é necessária.
O modificador ref readonly
será permitido para parâmetros.
Além dos métodos normais, ref readonly
será permitido para parâmetros do indexador (como in
, mas ao contrário de ref
), mas não será permitido para parâmetros de operador (como ref
, mas ao contrário de in
).
Os valores de parâmetro padrão serão permitidos para parâmetros ref readonly
, com um aviso, pois são equivalentes a passar rvalues.
Isso permite que os autores de API alterem parâmetros in
com valores padrão para parâmetros ref readonly
sem causar uma quebra de compatibilidade de código-fonte.
Verificações de tipos de valores
Observe que, embora o modificador de argumento ref
seja permitido para os parâmetros ref readonly
, nada muda com respeito às verificações de tipo de valor, ou seja,
-
ref
só pode ser usado com valores atribuíveis; - para passar referências de apenas leitura, é preciso usar o modificador de argumento
in
; - para passar rvalues, não é preciso usar nenhum modificador (o que resulta em um aviso para parâmetros de
ref readonly
, conforme descrito no resumo desta proposta).
Resolução de sobrecarga
A resolução de sobrecarga permitirá misturar ref
/ref readonly
/in
/sem anotações de chamada e modificadores de parâmetros, conforme indicado pela tabela no resumo desta proposta, ou seja, todos os casos permitidos e de aviso serão considerados como possíveis candidatos durante a resolução de sobrecarga.
Especificamente, há uma alteração no comportamento existente em que os métodos com o parâmetro in
corresponderão a chamadas com o argumento correspondente marcado como ref
— essa alteração será controlada pelo LangVersion.
No entanto, o aviso para passar um argumento sem modificador de local de chamada para um parâmetro ref readonly
será suprimido se o parâmetro for
- o receptor em uma invocação de método de extensão,
- usado implicitamente como parte do inicializador de coleção personalizada ou manipulador de cadeia de caracteres interpolada.
As sobrecargas por valor serão preferenciais em vez de sobrecargas ref readonly
caso não haja nenhum modificador de argumento (parâmetros in
têm o mesmo comportamento).
Conversões de método
Da mesma forma, para fins de conversões de função anônima [§10.7] e grupo de métodos [§10.8], esses modificadores são considerados compatíveis (mas qualquer conversão permitida entre modificadores diferentes resulta em um aviso):
- O parâmetro
ref readonly
do método de destino pode corresponder ao parâmetroin
ou aoref
do delegado. - O parâmetro
in
do método de destino tem permissão para corresponder ao parâmetroref readonly
ou, condicionado à LangVersion, ao parâmetroref
do delegado. - Observação: o parâmetro
ref
do método de destino não pode corresponder ao parâmetroin
nem aoref 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, as conversões de ponteiro de função implícita não serão permitidas se houver uma incompatibilidade entre modificadores de tipo de referência e conversões explícitas sempre serão permitidas sem avisos.
Correspondência de assinatura
Os membros declarados em um único tipo não podem diferir na assinatura apenas devido a 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 em um aviso no local da declaração [§7.6].
Isso não se aplica ao comparar a declaração partial
com sua implementação e ao comparar a assinatura do interceptor com a assinatura interceptada.
Observe que não há nenhuma alteração na substituição dos pares de modificadores ref
/in
e ref readonly
/ref
, eles não podem ser trocados, pois as assinaturas não são compatíveis em termos binários.
Para manter a consistência, o mesmo se aplica a outras finalidades de correspondência de assinatura (por exemplo, ocultação).
Codificação de metadados
Como lembrete,
- Os parâmetros
ref
são emitidos como tipos de byref simples (T&
em IL), - Os parâmetros
in
são comoref
e eles são anotados comSystem.Runtime.CompilerServices.IsReadOnlyAttribute
. No C# 7.3 e versões posteriores, eles também são emitidos com[in]
e, se forem virtuais, commodreq(System.Runtime.InteropServices.InAttribute)
.
Os parâmetros ref readonly
serão emitidos como [in] T&
, e 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 forem 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 dos parâmetros in
, nenhum [IsReadOnly]
será emitido para parâmetros ref readonly
para evitar o aumento do tamanho dos metadados e também para fazer com que versões mais antigas do compilador interpretem parâmetros ref readonly
como parâmetros ref
(e, portanto, ref
→ ref readonly
não será uma alteração interruptiva de origem mesmo entre diferentes versões do compilador).
Se não estiver incluído na compilação, o RequiresLocationAttribute
será correspondido pelo nome qualificado do namespace e sintetizado pelo compilador.
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
Nos ponteiros de função, os parâmetros in
são emitidos junto a modreq(System.Runtime.InteropServices.InAttribute)
(consulte a proposta de ponteiros de função ).
Os parâmetros ref readonly
serão emitidos sem esse modreq
, mas sim com modopt(System.Runtime.CompilerServices.RequiresLocationAttribute)
.
As versões mais antigas do compilador ignorarão modopt
e, portanto, interpretarão os parâmetros ref readonly
como parâmetros ref
(consistentes com o comportamento do compilador mais antigo para métodos normais com parâmetros ref readonly
conforme descrito acima) e novas versões do compilador com reconhecimento de modopt
o usarão para reconhecer parâmetros ref readonly
para emitir avisos durante conversões e invocações .
Para consistência com versões mais antigas do compilador, novas versões do compilador que possuem LangVersion <= 11
indicarão erros de 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 ocorrerá apenas para chamadores com LangVersion <= 11
ao alterar in
→ ref readonly
(se o ponteiro for invocado com o modificador de local de chamada in
), consistente com métodos normais.
Alterações da falha
O relaxamento de incompatibilidades ref
/in
na resolução de sobrecarga introduz uma mudança de quebra de comportamento, demonstrada 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";
}
No C# 11, a chamada se associa a E.M
; portanto, "E"
é impresso.
No C# 12, C.M
pode se vincular (com um aviso) e não são buscados escopos de extensão já que temos um candidato aplicável; portanto, "C"
é impresso.
Há também uma alteração radical na origem devido ao mesmo motivo.
O exemplo a seguir imprime "1"
no C# 11, mas, no C# 12, falha na compilação devido a um erro de ambiguidade.
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 nas invocações de método, mas como são causadas por alterações na resolução de sobrecarga, elas também podem ser acionadas para conversões de método.
Alternativas
Declarações de parâmetro
Os autores de API poderiam anotar parâmetros in
projetados para aceitar apenas lvalues com um atributo personalizado e fornecer um analisador para sinalizar usos incorretos.
Isso não permitiria que os autores de API alterassem assinaturas de APIs existentes que optassem por usar parâmetros ref
para não permitir rvalues.
Os chamadores dessas APIs ainda precisariam executar um trabalho extra para obter ref
se tiverem acesso apenas a uma variável ref readonly
.
Alterar essas APIs de ref
para [RequiresLocation] in
seria uma mudança que quebra a compatibilidade com o código-fonte (e, no caso de métodos virtuais, também uma mudança que quebra a compatibilidade binária).
Em vez de permitir o modificador ref readonly
, o compilador pode reconhecer quando um atributo especial (como [RequiresLocation]
) é aplicado a um parâmetro.
Isso foi discutido em LDM 2022-04-25, onde decidiu-se que isso é um recurso de linguagem, e não um analisador, por isso deve, portanto, parecer com um.
Verificações de tipos de valores
A passagem de lvalues sem modificadores para parâmetros ref readonly
poderia ser permitida sem avisos, similar aos parâmetros de byref implícitos do C++.
Isso foi discutido em LDM 2022-05-11, observando que a principal motivação para parâmetros ref readonly
são APIs que capturam ou retornam referências desses parâmetros, portanto, marcador de algum tipo é uma vantagem.
Passar rvalue para ref readonly
pode ser um erro, não um aviso.
Isso foi inicialmente aceito em LDM 2022-04-25, mas discussões posteriores por e-mail viabilizaram uma flexibilização disso, pois perderíamos a capacidade de alterar as APIs existentes sem interromper o uso pelos usuários.
in
pode ser o modificador de local de chamada "natural" para parâmetros ref readonly
e usar ref
pode resultar em avisos.
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 aceito inicialmente no LDM 2022-04-25.
No entanto, os avisos podem ser um ponto de atrito para os autores de 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 LDM pendente
Nenhuma das opções a seguir foi implementada no C# 12. Continuam sendo propostas potenciais.
Declarações de parâmetro
A ordenação inversa de modificadores (readonly ref
em vez de ref readonly
) poderia ser permitida.
Isso seria inconsistente com a maneira como readonly ref
é retornado e os campos se comportam (a ordenação inversa não é permitida ou significa algo diferente, respectivamente) e poderia entrar em conflito com parâmetros somente leitura se implementados no futuro.
Os valores padrão dos parâmetros podem representar um erro para os parâmetros do tipo ref readonly
.
Verificações de tipos de valores
Podem ser gerados erros em vez de avisos ao passar rvalues para parâmetros ref readonly
ou em caso de incompatibilidades entre anotações de chamada e modificadores de parâmetros.
Da mesma forma, valores modreq
especiais podem ser usados em vez de usar um atributo para garantir que os parâmetros ref readonly
sejam distintos dos parâmetros in
no nível binário.
Isso proporcionaria garantias mais fortes, portanto, seria bom para novas APIs, mas evitaria a adoção em APIs de runtime existentes que não podem introduzir alterações significativas.
As verificações de tipo de valor podem ser relaxadas para permitir que referências somente leitura sejam passadas através de ref
para os parâmetros de in
/ref readonly
.
Seria semelhante à forma como as atribuições ref e os retornos ref funcionam hoje—eles também permitem a passagem de referências como leitura única por meio do modificador ref
na expressão de origem.
No entanto, o ref
normalmente está próximo do local onde o alvo é declarado como ref readonly
, portanto, é claro que estamos passando uma referência como somente leitura (readonly), ao contrário das invocações cujos modificadores de argumento e parâmetro geralmente estão distantes.
Além disso, eles permitem que somente 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 tornaria praticamente obsoleto 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 de ref e retornos de ref).
Resolução de sobrecarga
A resolução de sobrecarga, substituição e conversão poderiam impedir a intercambiabilidade dos modificadores ref readonly
e in
.
A alteração da resolução de sobrecarga para parâmetros de in
existentes poderia ser tomada incondicionalmente (não considerando LangVersion), mas isso seria uma alteração significativa.
Invocar um método de extensão com o receptor ref readonly
pode resultar no aviso "O argumento 1 deve ser passado com a palavra-chave ref
ou in
", como ocorreria para invocações não-extensivas sem modificadores de local de chamada (o usuário pode corrigir esse aviso transformando a chamada do método de extensão em uma chamada de método estático).
O mesmo aviso pode ser relatado ao usar um inicializador de coleção personalizado ou um manipulador de cadeia de caracteres interpolada com o parâmetro ref readonly
, embora o usuário não possa contornar o problema.
As sobrecargas ref readonly
podem ser preferidas a sobrecargas por valor quando não há modificador no local de chamada ou pode haver um erro de ambiguidade.
Conversões de método
Poderíamos permitir que o parâmetro ref
do método de destino corresponda aos parâmetros in
e ref readonly
do delegado.
Isso permitiria que os autores de API alterassem, por exemplo, ref
para in
em assinaturas delegadas sem interromper seus usuários (consistentemente com o que é permitido para assinaturas de método normais).
No entanto, isso também resultaria na seguinte violação das garantias de 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
}
}
Conversões de ponteiro de função poderiam emitir um aviso sobre uma incompatibilidade de ref readonly
/ref
/in
, mas se quiséssemos condicionar isso à LangVersion, seria necessário um investimento significativo em implementação, pois as conversões de tipo atuais não precisam de acesso à compilação.
Além disso, embora a incompatibilidade seja atualmente um erro, é fácil para os usuários adicionar uma conversão para aceitar a incompatibilidade, se desejarem.
Codificação de metadados
Especificar RequiresLocationAttribute
na origem pode ser permitido, da mesma forma que atributos In
e Out
.
Como alternativa, pode ser um erro quando aplicado em outros contextos que não apenas parâmetros, da mesma forma que o atributo IsReadOnly
; para preservar o espaço de design adicional.
Parâmetros do ponteiro de função ref readonly
podem ser emitidos com diferentes combinações de modopt
/modreq
(observe que "quebra de origem" nesta tabela significa para chamadores com LangVersion <= 11
):
Modificadores | Pode ser reconhecido entre compilações | Compiladores antigos os veem 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, quebra de origem | Ok |
modreq(RequiresLocation) |
sim | não compatível | binário, quebra de origem | binário, quebra de origem |
modopt(RequiresLocation) |
sim | ref |
quebra binária | binário, quebra de origem |
Poderíamos emitir atributos [RequiresLocation]
e [IsReadOnly]
para parâmetros ref readonly
.
Em seguida, in
→ ref readonly
não seria uma alteração de quebra mesmo para versões mais antigas do compilador, mas ref
→ ref readonly
se tornaria uma alteração de quebra de código-fonte para versões mais antigas do compilador (pois interpretariam ref readonly
como in
, o que não permitiria os modificadores ref
) e para novas versões do compilador com LangVersion <= 11
(por questões de consistência).
Poderíamos tornar o comportamento de LangVersion <= 11
diferente do comportamento de 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 sempre ser permitido sem erros.
Alterações da falha
Esta proposta sugere aceitar uma alteração de comportamento disruptivo porque deve ser rara de ocorrer, é controlada por LangVersion, e os usuários podem contornar isso chamando explicitamente o método de extensão. Em vez disso, poderíamos atenuá-lo por
- não permitir a incompatibilidade de
ref
/in
(que só impediria a migração parain
para APIs antigas que usavamref
porquein
ainda não estava disponível), - modificando as regras de resolução de sobrecarga para continuar procurando uma correspondência melhor (determinada pelas regras de aperfeiçoamento especificadas abaixo) quando há uma incompatibilidade de tipo ref introduzida nesta proposta,
- ou, como alternativa, continuar apenas para
ref
versusin
incompatibilidade, não para os outros (ref readonly
vs.ref
/in
/por valor).
- ou, como alternativa, continuar apenas para
Regras de aperfeiçoamento
O exemplo a seguir resulta em três erros de ambiguidade para as três invocações de M
.
Poderíamos adicionar novas regras de aperfeiçoamento para resolver as ambiguidades.
Isso também resolveria a mudança de ruptura no código-fonte descrita anteriormente.
Uma maneira seria fazer o exemplo imprimir 221
(onde o parâmetro ref readonly
é correspondido ao argumento in
, pois seria um aviso chamá-lo sem um modificador, enquanto que para o parâmetro in
é 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 aperfeiçoamento podem marcar como pior o parâmetro cujo argumento possa ter sido passado com um modificador de argumento diferente para torná-lo melhor.
Ou seja, 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 em vez de um parâmetro in
, para que o usuário possa passar o argumento por valor e escolher o parâmetro in
.
Essa 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 de seus parâmetros for melhor e nenhum for pior do que o parâmetro correspondente de outra sobrecarga).
argumento | parâmetro melhor | parâmetro pior |
---|---|---|
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 da mesma forma.
O exemplo a seguir resulta em dois erros de ambiguidade para as duas atribuições delegadas.
Novas regras de aperfeiçoamento podem preferir um parâmetro de método cujo modificador de referência corresponde ao modificador de referência do parâmetro de delegado de destino correspondente, em vez de um que tenha uma incompatibilidade.
Portanto, 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: funcionalidade aceita
- LDM 2022-05-09: discussão dividida em três partes
- LDM 2022-05-11: é permitida
ref
e nenhuma anotação de local de chamada para parâmetrosref readonly
C# feature specifications