Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
FxCop Rule VisitMethodCall -> Methoden calls werden nicht aufgelöst
rollerfreak2
myCSharp.de - Member

Avatar #avatar-3271.jpg


Dabei seit:
Beiträge: 928

Themenstarter:

FxCop Rule VisitMethodCall -> Methoden calls werden nicht aufgelöst

beantworten | zitieren | melden

Ich habe ein Problem mit einer eigenen FxCop Regel. Ich möchte alle Methoden Aufrufe analysieren und dabei werden nicht alle aufgelöst. Speziell die innerhalb eines "yield return" werden nicht aufgelöst. Gegeben ist exemplarisch folgendes:


public interface IInterface
{
    void Foo();
}

internal class Interface : IInterface
{
    private readonly object m_Obj;

    public Interface(object obj)
    {
        m_Obj = obj;
    }

    public void Foo()
    {
        throw new NotImplementedException();
    }
}

class Program
{
    static void Main(string[] args)
    {
        var interfaces = GetInterfaces();
    }

    private static IEnumerable<IInterface> GetInterfaces()
    {
        yield return new Interface(Resolve());
    }

    private static object Resolve()
    {
        return new object();
    }
}

Worum es mir geht ist der Methoden Call von Resolve() innerhalb des yield return. Der IL Code sieht so aus:

.method private hidebysig static class [mscorlib]System.Collections.Generic.IEnumerable`1<class OpCode.IInterface> 
        GetInterfaces() cil managed
{
  // Code size       14 (0xe)
  .maxstack  1
  .locals init ([0] class OpCode.Program/'<GetInterfaces>d__0' V_0,
           [1] class [mscorlib]System.Collections.Generic.IEnumerable`1<class OpCode.IInterface> V_1)
  IL_0000:  ldc.i4.s   -2
  IL_0002:  newobj     instance void OpCode.Program/'<GetInterfaces>d__0'::.ctor(int32)
  IL_0007:  stloc.0
  IL_0008:  ldloc.0
  IL_0009:  stloc.1
  IL_000a:  br.s       IL_000c
  IL_000c:  ldloc.1
  IL_000d:  ret
} // end of method Program::GetInterfaces

Im FxCop hab ich schon mehreres Versucht. Es wird für die Rückgabe ein Compile Generiertes Object zurück gegeben. Soweit so klar. Aber ich komme einfach nicht an den MethodCall vom Resolve() ran.


...
Visit(method.Body);
foreach (InstanceInitializer instanceInitializer in method.Instructions().Select(t => t.Value).OfType<InstanceInitializer>())
{
    Visit(instanceInitializer.Body);
}
...

Weiß einer wie ich wirklich an ALLE Methodenaufrufe heran komme? Gleiches Problem wird sicherlich auch bei Lamda's auftauchen.
Again what learned...
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo rollerfreak2,

GetInterfaces ruft Resolve wirklich nie auf. Resolve würde erst aufgerufen werden, wenn das von GetInterfaces zurückgegebene IEnumerable<> tatsächlich enummeriert werden würde. Das passiert in deinem Code(ausschnitt) aber nirgends. Im Ergebnis wird Resolve an keiner Stelle aufgerufen. Der Compiler könnte theoretisch - solange tatsächlich nie und nirgends enummeriert wird - im Grunde so weit gehen, und die Methode Resolve komplett wegoptimieren.

Es ist hat so, dass bei Compiler Magic die Dinge nicht so sind, wie sie sich im Code darstellen. Damit muss man leben.

herbivore
private Nachricht | Beiträge des Benutzers
rollerfreak2
myCSharp.de - Member

Avatar #avatar-3271.jpg


Dabei seit:
Beiträge: 928

Themenstarter:

beantworten | zitieren | melden

Hi herbivore,

das hab ich auch erst gedacht. Aber selbst wenn ich im Main das Foo rufe um das Enumerable auszuführen sieht der IL identisch aus.


public static void Main(string[] args)
{
    foreach (var itf in GetInterfaces())
    {
        itf.Foo();
    }
}

.method public hidebysig static class [mscorlib]System.Collections.Generic.IEnumerable`1<class OpCode.IInterface> 
        GetInterfaces() cil managed
{
  // Code size       14 (0xe)
  .maxstack  1
  .locals init ([0] class OpCode.Program/'<GetInterfaces>d__0' V_0,
           [1] class [mscorlib]System.Collections.Generic.IEnumerable`1<class OpCode.IInterface> V_1)
  IL_0000:  ldc.i4.s   -2
  IL_0002:  newobj     instance void OpCode.Program/'<GetInterfaces>d__0'::.ctor(int32)
  IL_0007:  stloc.0
  IL_0008:  ldloc.0
  IL_0009:  stloc.1
  IL_000a:  br.s       IL_000c
  IL_000c:  ldloc.1
  IL_000d:  ret
} // end of method Program::GetInterfaces
Again what learned...
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo rollerfreak2,

wie ich schon schrieb: "GetInterfaces ruft Resolve wirklich nie auf."

Aufgerufen wird Resolve (indirekt) vom foreach im Main.

Das macht eben die Compiler-Magie.

herbivore
private Nachricht | Beiträge des Benutzers
rollerfreak2
myCSharp.de - Member

Avatar #avatar-3271.jpg


Dabei seit:
Beiträge: 928

Themenstarter:

beantworten | zitieren | melden

Hab das Problem jetzt gefunden. Das Resolve wird halt nicht direkt sondern indirekt gerufen.

Wenn man den nested Type der vom Compiler erzeugt wird mit analysiert, dann findet man in der MoveNext Implementierung den Resolve Aufruf. (IL_0026)

.method private hidebysig newslot virtual final 
        instance bool  MoveNext() cil managed
{
  .override [mscorlib]System.Collections.IEnumerator::MoveNext
  // Code size       78 (0x4e)
  .maxstack  2
  .locals init ([0] bool CS$1$0000,
           [1] int32 CS$4$0001)
  IL_0000:  ldarg.0
  IL_0001:  ldfld      int32 OpCode.Program/'<GetInterfaces>d__0'::'<>1__state'
  IL_0006:  stloc.1
  IL_0007:  ldloc.1
  IL_0008:  switch     ( 
                        IL_0019,
                        IL_0017)
  IL_0015:  br.s       IL_001b
  IL_0017:  br.s       IL_0040
  IL_0019:  br.s       IL_001d
  IL_001b:  br.s       IL_0048
  IL_001d:  ldarg.0
  IL_001e:  ldc.i4.m1
  IL_001f:  stfld      int32 OpCode.Program/'<GetInterfaces>d__0'::'<>1__state'
  IL_0024:  nop
  IL_0025:  ldarg.0
  IL_0026:  call       object OpCode.Program::Resolve()
  IL_002b:  newobj     instance void OpCode.Interface::.ctor(object)
  IL_0030:  stfld      class OpCode.IInterface OpCode.Program/'<GetInterfaces>d__0'::'<>2__current'
  IL_0035:  ldarg.0
  IL_0036:  ldc.i4.1
  IL_0037:  stfld      int32 OpCode.Program/'<GetInterfaces>d__0'::'<>1__state'
  IL_003c:  ldc.i4.1
  IL_003d:  stloc.0
  IL_003e:  br.s       IL_004c
  IL_0040:  ldarg.0
  IL_0041:  ldc.i4.m1
  IL_0042:  stfld      int32 OpCode.Program/'<GetInterfaces>d__0'::'<>1__state'
  IL_0047:  nop
  IL_0048:  ldc.i4.0
  IL_0049:  stloc.0
  IL_004a:  br.s       IL_004c
  IL_004c:  ldloc.0
  IL_004d:  ret
} // end of method '<GetInterfaces>d__0'::MoveNext
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von rollerfreak2 am .
Again what learned...
private Nachricht | Beiträge des Benutzers