C # - Verditype lik metode - hvorfor kompilatoren bruk refleksjon?

stemmer
14

Jeg kom over noe ganske merkelig for meg: når du bruker lik () -metoden på en verditype (og hvis denne metoden ikke er blitt overstyrt, selvfølgelig) du får noe veldig veldig sakte - felt er sammenlignet 12:59 hjelp refleksjon! Som i :

public struct MyStruct{
   int i;
}

   (...)

   MyStruct s, t;
   s.i = 0;
   t.i = 1;
   if ( s.Equals( t ))   /*  s.i will be compared to t.i via reflection here. */
      (...)

Mitt spørsmål: Hvorfor C # kompilatoren genererer ikke en enkel metode for å sammenligne verdityper? Noe som (i MyStruct definisjon):

   public override bool Equals( Object o ){
      if ( this.i == o.i )
         return true;
      else
         return false;
   }

Kompilatoren vet hva som er de områdene MyStruct på kompilering, hvorfor det vente til runtime å nummerere MyStruct felt?

Veldig merkelig for meg.

Takk :)

Lagt : Beklager, jeg bare innse det, selvfølgelig, Equalser ikke et språk søkeord, men en kjøretids metode ... Kompilatoren er helt uvitende om denne metoden. Så det gjør sens her for å bruke refleksjon.

Publisert på 17/06/2009 klokken 20:35
kilden bruker
På andre språk...                            


3 svar

stemmer
10

Det bruker ikke refleksjon når det ikke trenger å . Det bare sammenligne verdier litt etter litt i tilfelle structhvis det kan gjøre det. Men det hvis noen av structmedlemmene (eller medlemmer av medlemmer, eventuelle etterkommere) styrer object.Equalsog gir sin egen gjennomføring, selvsagt, det kan ikke stole på bit-for-bit sammenligning å beregne returverdien.

Grunnen til det er treg er at parameteren som Equalser av type objectog verdityper må være innrammet å bli behandlet som en object. Boksing innebærer tildeling av minne på haugen og minne kopiering verditypen til stedet.

Du kan gi en overbelastning for manuelt Equalsmetode som tar din egen structsom parameter for å hindre boksing:

public bool Equals(MyStruct obj) {
     return obj.i == i;
}
Svarte 17/06/2009 kl. 20:41
kilden bruker

stemmer
9

Det følgende er decompiled ValueType.Equals metode fra mscorlib:

public override bool Equals(object obj)
{
    if (obj == null)
    {
        return false;
    }
    RuntimeType type = (RuntimeType) base.GetType();
    RuntimeType type2 = (RuntimeType) obj.GetType();
    if (type2 != type)
    {
        return false;
    }
    object a = this;
    if (CanCompareBits(this))
    {
        return FastEqualsCheck(a, obj);
    }
    FieldInfo[] fields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
    for (int i = 0; i < fields.Length; i++)
    {
        object obj3 = ((RtFieldInfo) fields[i]).InternalGetValue(a, false);
        object obj4 = ((RtFieldInfo) fields[i]).InternalGetValue(obj, false);
        if (obj3 == null)
        {
            if (obj4 != null)
            {
                return false;
            }
        }
        else if (!obj3.Equals(obj4))
        {
            return false;
        }
    }
    return true;
}

Når det er mulig, vil en bitvis sammenligning gjøres (merk CanCompareBits og FastEqualsCheck, som begge er definert som InternalCall. JIT ville formodentlig injisere den aktuelle koden her. Om hvorfor det er så treg, jeg kunne ikke fortelle deg .

Svarte 17/06/2009 kl. 20:50
kilden bruker

stemmer
3

Ideen om en kompilator generert funksjon er berettiget.

Tenker effektene men jeg tror det språket design team gjorde det riktig. Compilergenerated metoder kjent fra C ++ er vanskelig å forstå for nybegynnere. Kan se hva som ville skje i C # med automatisk genererte struct.Equals:

Som det er nå, er begrepet .Equals () enkel:

  • Hver struct arver lik fra ValueType.
  • Hvis overstyrt, tilpasset lik metoden gjelder.

Hvis kompilatoren alltid ville skape lik metoden, kunne vi ha:

  • Hver struct arver lik fra Object. (ValueType ikke lenger ville gjennomføre sin egen versjon)
  • Object.Equals er nå alltid (!) ANT, enten av kompilatoren som genereres lik metoden eller ved den brukere gjennomføringen

Nå vår struct har en autogenerert overstyring metode som koden leseren ikke se! Så hvordan vet du at basismetoden Object.Equals ikke gjelder for din struct? Ved å lære alle tilfeller av automatisk kompilatoren genererte metoder. Og dette er akkurat en av de byrder lære C ++.

Vil vurdere det god beslutning å forlate effektiv struct lik for brukeren og holde begrepene enkel, krever en standard standard lik metode.

Når det er sagt, ytelse kritiske structs skal overstyre lik. Koden nedenfor viser

3606 vs 53 millisekunder , målt på .net 4.5.1

Denne ytelsesgevinst er absolutt grunn til å unngå virtuelle lik, men uansett, så hvis de virtuelle Object.Equals ville bli kalt gevinst ville være mye lavere. Ytelses kritiske tilfeller vil ikke kalle Object.Equals imidlertid slik at gevinsten her vil gjelde.

using System;
using System.Diagnostics;

struct A
{
    public int X;
    public int Y;
}

struct B : IEquatable<B>
{
    public bool Equals(B other)
    {
        return this.X == other.X && this.Y == other.Y;
    }

    public override bool Equals(object obj)
    {
        return obj is B && Equals((B)obj);
    }

    public int X;
    public int Y;
}


class Program
{
    static void Main(string[] args)
    {
        var N = 100000000;

        A a = new A();
        a.X = 73;
        a.Y = 42;
        A aa = new A();
        a.X = 173;
        a.Y = 142;

        var sw = Stopwatch.StartNew();
        for (int i = 0; i < N; i++)
        {
            if (a.Equals(aa))
            {
                Console.WriteLine("never ever");
            }
        }
        sw.Stop();
        Console.WriteLine(sw.ElapsedMilliseconds);

        B b = new B();
        b.X = 73;
        b.Y = 42;
        B bb = new B();
        b.X = 173;
        b.Y = 142;

        sw = Stopwatch.StartNew();
        for (int i = 0; i < N; i++)
        {
            if (b.Equals(bb))
            {
                Console.WriteLine("never ever");
            }
        }
        sw.Stop();
        Console.WriteLine(sw.ElapsedMilliseconds);
    }
}

se også http://blog.martindoms.com/2011/01/03/c-tip-override-equals-on-value-types-for-better-performance/

Svarte 20/11/2013 kl. 22:41
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more