2010-06-03 4 views
16

Ich habe eine Reihe von Methoden mit unterschiedlichen Signaturen. Diese Methoden interagieren mit einer fragilen Datenverbindung, so verwenden wir oft eine Hilfsklasse Wiederholungen/Reconnects auszuführen, usw. Wie so:Kann ich das Decorator-Muster verwenden, um einen Methodenkörper zu umbrechen?

MyHelper.PerformCall(() => { doStuffWithData(parameters...) }); 

Und das funktioniert gut, aber es kann den Code ein wenig cluttery machen. Was würde ich es vorziehen, zu tun ist, die Methoden dekorieren, die mit der Datenverbindung in Wechselwirkung treten, wie so:

[InteractsWithData] 
protected string doStuffWithData(parameters...) 
{ 
    // do stuff... 
} 

Und dann im Wesentlichen, wann immer doStuffWithData genannt wird, würde der Körper dieser Methode in als Action-MyHelper.PerformCall() weitergegeben werden. Wie mache ich das?

+4

Frage MSFT, um eine Funktion zu .Net 5.0 einzuschleichen? –

Antwort

16

.NET-Attribute sind Metadaten, keine Dekoratoren/aktiven Komponenten, die automatisch aufgerufen werden. Es gibt keinen Weg, dieses Verhalten zu erreichen.

Sie können Attribute zum Implementieren von Dekoratoren verwenden, indem Sie den Dekoratorcode in die Attribute-Klasse einfügen und die Methode mit einer Hilfsmethode aufrufen, die die Methode in der Attributklasse mit Reflection aufruft. Aber ich bin mir nicht sicher, ob dies eine große Verbesserung wäre, wenn man die "Decorator-Methode" direkt nennt.

"Decorator-Attribut":

[AttributeUsage(AttributeTargets.Method)] 
public class MyDecorator : Attribute 
{ 
    public void PerformCall(Action action) 
    { 
     // invoke action (or not) 
    } 
} 

Methode:

[MyDecorator] 
void MyMethod() 
{ 
} 

Usage:

InvokeWithDecorator(() => MyMethod()); 

Helper-Methode:

void InvokeWithDecorator(Expression<Func<?>> expression) 
{ 
    // complicated stuff to look up attribute using reflection 
} 

Hier finden Sie aktuelle Rahmenbedingungen für Aspect Oriented Programming in C#. Diese können bieten, was Sie wollen.

+0

Hätten Sie etwas dagegen, ein schnelles Codebeispiel einzutippen? Mir fällt es schwer, mir das vorzustellen. –

+2

Beispiel hinzugefügt .. – dtb

+0

Awesome, danke, und ich denke, du hast Recht - ich habe nicht wirklich viel Vorteil über den Aufruf der Helfer direkt. –

3

Diese Art von Problem ist ziemlich genau das, was AOP (aspektorientierte Programmierung) zu lösen versucht. Tools wie PostSharp können übergreifende Probleme bieten, indem sie den kompilierten Code neu schreiben. Scott Hanselmans Podcast hat vor kurzem über AOP gesprochen, also könnte es sich lohnen, zuzuhören.

1

Auschecken aspect oriented frameworks. Seien Sie sich jedoch bewusst, dass das Vorhandensein von AoP-Funktionen Ihr Programm schwerer zu verwalten macht, obwohl sie die Komplexität in jeder Methode verbergen. Es ist ein Kompromiss.

1

Es scheint so, als ob das, was Sie wollen, dem Verhalten eines IoC-Containers oder eines Test-Runner-Frameworks ähnelt, in dem es nicht tatsächlich von Ihrer Assembly ausgeführt wird, sondern eine dynamisch emittierte Assembly um Ihren Code herum ausführt. (Intelligentere Leute als ich dieses AOP in anderen Antworten genannt)

So vielleicht in einem Stub für Ihre App könnten Sie die anderen Baugruppen scannen, diese emittierten Baugruppen erstellen (die MyHelper.PerformCall mit dem Körper der eingerichteten Methoden aufrufen) dann läuft Ihr Programm gegen den ausgegebenen Code.

Auf keinen Fall würde ich den Weg zu versuchen, um dies zu schreiben, ohne zu evaluieren, ob einige bestehende AOP-Framework erreichen könnte, was Sie brauchen. HTH>

0

Sehen Sie, dass Sie bereit sind, eine Codezeile zu jeder Methode hinzuzufügen, die dies benötigt, warum nicht einfach den Aufruf von MyHelper innerhalb der Methode selbst, so?

protected string doStuffWithData(parameters...) 
{ 
    MyHelper.PerformCall(() => { doStuffWithDataCore(parameters...) }); 
} 

private string doStuffWithDataCore(parameters...) { 
    //Do stuff here 
} 
+0

Ja, das mache ich gerade. –

+1

Was macht dann das Hinzufügen des Attributs für Sie? – Sijin

+1

Ich denke, es könnte den Code einfacher zu lesen und zu pflegen machen. –

4

Ohne die Verwendung von Gode-Generation können Sie nicht viel dagegen tun. Sie könnten wahrscheinlich die Syntax verbessern.

Aber was ist mit einer Erweiterungsmethode?

class static MyHelper 
{ 
    Wrap<T>(this object service, Action<T> action) 
    { 
    // check attribute and wrap call 
    } 

} 

Nutzung:

RawFoo foo = ... 
foo.Wrap(x => x.doStuffWithData(parameters...)); 

Dies ist trivial, aber man kann nicht sicherstellen, dass Wrap verwendet worden war.

Sie könnten einen generischen Decorator implementieren. Dieser Decorator wird einmal verwendet, um den Service zu umbrechen, und Sie können ihn dann nicht ohne Umbruch aufrufen.

class Decorator<T> 
{ 
    private T implementor; 

    Decorator(T implementor) 
    { 
     this.implementor = implementor; 
    } 

    void Perform<T>(Action<T> action) 
    { 
     // check attribute here to know if wrapping is needed 
     if (interactsWithData) 
     { 
     MyHelper.PerformCall(() => { action(implementor) }); 
     } 
     else 
     { 
     action(implementor); 
     } 
    } 
} 

static class DecoratorExtensions 
{ 
    public static Decorator<T> CreateDecorator<T>(T service) 
    { 
     return new Decorator<T>(service); 
    } 
} 

Verbrauch:

// after wrapping, it can't be used the wrong way anymore. 
ExtendedFoo foo = rawFoo.CreateDecorator(); 
foo.Perform(x => x.doStuffWithData(parameters...)); 
14

Also, ich ging auf eine AOP-Sitzung an diesem Wochenende, und hier ist ein Weg, um es mit Postsharp zu tun:

[Serializable] 
public class MyAOPThing : MethodInterceptionAspect 
{ 
    public override void OnInvoke(MethodInterceptionArgs args) 
    { 
     Console.WriteLine("OnInvoke! before"); 
     args.Proceed(); 
     Console.WriteLine("OnInvoke! after"); 
    } 
} 

Und dann Methoden dekorieren mit [MyAOPThing]. Einfach!

+2

Dies sollte die beste Antwort sein. Danke fürs Schreiben. –

+0

PostSharp ist nicht kostenlos –

+0

Die Frage sagt nichts über den Preis. Außerdem gibt es eine kostenlose Postsharp-Lizenz: https://www.postsharp.net/download –

Verwandte Themen