Hvorfor kan jeg ikke bestå en ejendom eller indexer som en ref parameter, når .NET reflektor viser, at det er gjort på .NET Framework?

Okay, jeg vil klippe og klistre fra .NET reflektor for at vise, hvad jeg forsøger at gøre:

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

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

    //More irrelevant code...
}

Denne linje kode kommer lige ud af Systemet.Web.Sikkerhed.SqlMembershipProvider.UpdateUser (System.Web.dll v2.0.50727).NET Framework.

Den SecUtility.CheckParameter kræver en reference værdi, som den første parameter, som de går forbi en ejendom af brugeren gået ind som argument.

Definition af CheckParameter kode er:

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

Alt, hvad den gør, giver mening på papir… så jeg banke en hurtig lille prototype for et eller andet sted ville jeg gerne bruge noget lignende:

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.
    }
}

Denne kode vil ikke compile – fejl-shows som:

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

Fair nok… men hvorfor vil min kode tillade mig at gøre noget, der ser ud til at være i den .NET Framework kode base? Er dette en fejl med måde .NET Reflektor er at fortolke de DLL-eller er det en fejl med den måde, jeg fortolker deres kode?

Du er ved hjælp af en automatisk ejendom. Når det bliver kompileret, det er blevet til to funktioner. Så rammer ikke kan passere en henvisning til to funktioner i noget andet.
det ville være forståeligt. Men i den kode, der fik mig til at bemærke dette problem, jeg bruger samme MembershipUser klasse, der refereres til i de Rammer, jeg er i præcis samme måde, – hvordan kommer derfor, at det kan gøres indenfor rammerne, men ikke udenfor?
Hvor er @JonSkeet, når du har brug for ham…
Jeg kommer, jeg kommer… give mig et par minutter mere 🙂
Ser ud som om det er reflektor spørgsmål. I IL-kode lokal variabel oprettes, på stakken og videre til CheckParameter () – metoden

OriginalForfatteren BenAlabaster | 2009-11-27

4 svar

  1. 15

    Jeg synes, det er nogle dårlige fortolkning fra Reflektor. Faktisk, hvis du skriver kode som dette:

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

    og samle det på Release mode, vil du se dette i Reflektoren:

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

    Husk, at C# compiler er ikke at producere C# kode, men IL, så hvad du ser i Reflektoren er ikke altid virkeligheden. Så til klart at forstå, hvad der foregår under kølerhjelmen, du kan kig på den rigtige kode, der produceres af compileren:

    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)

    Det er klart, at en lokal variabel er anvendt.

    men er det ikke semantisk forskellige? Er det ikke brugernavn nu en kopi af x.Klassenavn og vi går en henvisning til strengen “brugernavn” ikke en henvisning til strengen “x.Klassenavn”…
    at frigive tilstand kode ekstrakt nu har mig skrabe mit hoved… hvordan er det at ændre koden til noget, jeg ikke kan kode selv, fordi oversætteren ikke tillade det?
    Samme ting i Debug mode 🙂
    Ben: ja, det er semantisk forskellige. Dette er grunden til, Darin siger, at det er dårlig tolkning fra Reflektor. Reflektor bør være at vise brugeren.Brugernavn bliver tildelt et lokale, og de lokale er gået med ref til CheckParameter. Debug eller Release mode ikke påvirke dette: hvad Darin kilde og “Reflectored” kode viser, er, at Reflektoren, dekompilering er forkert-det er semantisk forskellige fra hans kilde-kode (og ulovlig, som du har observeret).

    OriginalForfatteren Darin Dimitrov

  2. 6

    Det er en reflektor fejl. Det er ikke rigtigt, passerer den ejendom som reference.

    Her er nogle C# kode, som vil gengive det.

    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)
        {
        }
    }

    Reflektor viser denne kode for Foo:

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

    Ikke kun er denne ugyldig C#, men det er misvisende – det tyder på, at ændringer, der er foretaget x inden Bar en eller anden måde ville ændre p.Name – hvis det er ikke tilfældet, når man ser på den oprindelige C# kode.

    I din oprindelige prøve, giver det endnu mindre mening, da UserName er en read-only ejendom!

    Tak for dit input 🙂
    Min oprindelige stikprøve er klippet og klistret, lige fra reflektor, som er, hvad der fik mig til at skrabe mit hoved
    når jeg siger “fra reflektor” mener jeg selvfølgelig “.NET Reflektor ‘ s fortolkning af System.Web.dll (v2.0.50727)” – jeg ved, du er en pernittengryn for præcis terminologi 😛
    Min “Reflektor viser denne kode…” bit blev klippet og klistret, lige fra reflektor for 🙂
    Yderligere spørgsmål til dig så: jeg ved ikke, hvordan Red Gate ‘ s Reflektor virker under dynen, jeg er heller ikke stor med IL. Er Red Gates’ reflektor bygget på .NET refleksion, og derfor er dette en begrænsning med .NET Refleksion eller er det et problem, at det kun rammer Reflektoren værktøj?

    OriginalForfatteren Jon Skeet

  3. 1

    Prøve at sætte værdien af ejendommen til en variabel, før den ledes til den funktion.

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

    Det er ikke den mest elegante løsning, men det skal pege dig i den rigtige retning. Som Yuriy sagde i sin kommentar ovenfor, at dens nok noget at gøre med det faktum, at du ikke er eksplicit, hvorved en get og set for ejendommen.

    Jeg havde allerede skrevet det ud som semantisk forskellige. Fordi jeg var efter en henvisning til x.Klassenavn. myClassName ville nu være en kopi af strengen, og jeg vil komme forbi en henvisning til kopi. Men nu @Darin Dimitrov har mig at vide, om release mode kompilation…

    OriginalForfatteren Kyle Trauberman

  4. 0

    Når du passerer en variabel som en ref eller ud, de kalder faktisk point til den hukommelse, hvor det oprindeligt er placeret. Så hvis du er tilladt at passere den ejendom, som en reference, betyder det, at du gør klassen medlem usammenhængende. Dette er årsagen til dette problem.

    OriginalForfatteren WAP Guy

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *