Por que não posso passar uma propriedade ou indexador como um parâmetro ref quando .NET refletor mostra que ele é feito no .NET Framework?

StackOverflow https://stackoverflow.com/questions/1810785

  •  05-07-2019
  •  | 
  •  

Pergunta

Ok, eu vou cortar e colar a partir .NET refletor para demonstrar o que estou tentando fazer:

public override void UpdateUser(MembershipUser user)
{
    //A bunch of irrelevant code...

    SecUtility.CheckParameter(ref user.UserName, true, true, true, 0x100, "UserName");

    //More irrelevant code...
}

Esta linha de código sai direito de System.Web.Security.SqlMembershipProvider.UpdateUser (System.Web.dll v2.0.50727) no .NET Framework.

O SecUtility.CheckParameter requer um valor de referência como o primeiro parâmetro, a que está passando uma propriedade do usuário passado como argumento.

A definição do código CheckParameter é:

internal static void CheckParameter(ref string param, bool checkForNull, bool checkIfEmpty, bool checkForCommas, int maxSize, string paramName)
{
    //Code omitted for brevity
}

Tudo que está fazendo faz sentido - no papel ... então eu bato um pouco protótipo rápida para um lugar que eu gostaria de usar algo semelhante:

public class DummyClass
{
    public string ClassName{ get; set; }
}

public class Program
{
    private static DoSomething(ref string value)
    {
        //Do something with the value passed in
    }

    public static Main(string[] args)
    {
        DummyClass x = new DummyClass() { ClassName = "Hello World" };

        DoSomething(ref x.ClassName); //This line has a red squiggly underline 
                                      //under x.ClassName indicating the 
                                      //error provided below.
    }
}

Este código não irá compilar - os shows de erro como:

"A property or indexer may not be passed as an out or ref parameter"

Fair suficiente ... mas por que não o meu código, permita-me fazer algo que parece estar na base de código .NET Framework? É este um erro com o caminho NET Reflector é interpretar a DLL ou isso é um erro com a maneira que eu estou interpretando seu código?

Foi útil?

Solução

Eu acho que é alguma má interpretação do refletor. Na verdade, se você escrever seu código como este:

static void Main(string[] args)
{
    DummyClass x = new DummyClass();
    string username = x.ClassName;
    DoSomething(ref username);
}

e compilá-lo no modo de versão você vai ver isso no refletor:

static void Main(string[] args)
{
    DummyClass x = new DummyClass();
    DoSomething(ref x.ClassName);
}

Lembre-se que o compilador C # não está produzindo código C #, mas IL modo que você vê no refletor nem sempre é a realidade. Então, para entender claramente o que está acontecendo sob o capô que você pode olhar para o verdadeiro código produzido pelo compilador:

L_000f: callvirt instance string System.Web.Security.MembershipUser::get_UserName()
L_0014: stloc.0 
L_0015: ldloca.s str
L_0017: ldc.i4.1 
L_0018: ldc.i4.1 
L_0019: ldc.i4.1 
L_001a: ldc.i4 0x100
L_001f: ldstr "UserName"
L_0024: call void System.Web.Util.SecUtility::CheckParameter(string&, bool, bool, bool, int32, string)

É claro que uma variável local é usado.

Outras dicas

É um bug refletor. Não é realmente passando a propriedade por referência.

Aqui está algum código C # que irá reproduzi-lo.

using System;

class Person
{
    public string Name { get; set; }
}

class Test
{
    static void Main(){} // Just make it easier to compile

    static void Foo(Person p)
    {
        string tmp = p.Name;
        Bar(ref tmp);
    }

    static void Bar(ref string x)
    {
    }
}

Refletor mostra este código para Foo:

private static void Foo(Person p)
{
    Bar(ref p.Name);
}

Não só isto é inválida C #, mas é enganosa - isso sugeriria que as alterações feitas x dentro Bar de alguma forma modificar p.Name -. Em que esse não é o caso quando você olha para o código original C #

Em sua amostra original, que faz ainda menos sentido como UserName é uma propriedade somente leitura!

Tente definir o valor da propriedade a uma variável antes de passá-lo para a função.

string myClassName = x.ClassName
DoSomething(ref myClassName);

A sua não é a solução mais elegante, mas deve apontar na direção certa. Como Yuriy disse em seu comentário acima, seu provavelmente algo a ver com o fato de que você não está declarando explicitamente um get e set para a propriedade.

Quando você passar uma variável como um ref ou fora, a chamada realmente aponta para a memória onde é originalmente localizada. Então, se você tem permissão para passar a propriedade como uma referência, isso significa que você está fazendo o inconsistente membro da classe. Esta é a razão por trás deste problema.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top