2015-07-01 5 views
6

Ich habe eine Klasse, wo jede Methode die gleiche Art und Weise beginnt:Gibt es eine elegante Möglichkeit, jede Methode in einer Klasse mit einem bestimmten Codeblock in C# zu beginnen?

internal class Foo { 
    public void Bar() { 
    if (!FooIsEnabled) return; 
    //... 
    } 
    public void Baz() { 
    if (!FooIsEnabled) return; 
    //... 
    } 
    public void Bat() { 
    if (!FooIsEnabled) return; 
    //... 
    } 
} 

Gibt es eine nette Art und Weise (und hoffentlich nicht schreibt jedes Mal), um den FooIsEnabled Teil für jede öffentliche Methode in der Klasse zu verlangen?

Ich überprüfe Is there an elegant way to make every method in a class start with a certain block of code?, aber diese Frage ist für Java, und ihre Antwort verwenden Java Library.

+0

Sie könnten etwas wie DynamicProxy verwenden, um dies zur Laufzeit zu weben. – Sneal

+0

Die Antwort ist ziemlich genau die gleiche wie die Java - Aspekt - orientierte Programmierung (z. B. PostSharp) oder dynamische Proxies. Oder natürlich, Code-Generierung - machen Sie einfach eine einfache T4-Vorlage, um den Proxy zum Zeitpunkt der Kompilierung zu generieren. – Luaan

+0

Es gibt sogar Fody als Alternative ... die Baugruppe nach dem Kompilieren modifizieren. Beachten Sie, dass .NET keine In-Sprache 'java.lang.reflect.Proxy' hat. – xanatos

Antwort

7

Das Prinzip, nach dem Sie suchen, ist Interception aus der Domäne Aspect Oriented Programming oder AOP.

Während C# nicht direkt es unterstützt leider gibt es solide Auswahl:

  1. Postsharp
  2. Unity Interception
  3. Spring.NET
  4. Castle Interceptors

Wenn ich Zeit morgen bekommen, werde ich Koche ein Beispiel für dich ...

+0

Don [nicht vergessen Castle Interceptors] (https://github.com/castleproject/ Windsor/Blob/Meister/Dokumente/Interceptors.md) –

4

Ich glaube nicht, dass Sie das zusätzliche Durcheinander in den Bar-, Baz-, Bat-Methoden leicht loswerden können, aber Sie können es einfacher machen, indem Sie eine Methode zum Ausführen von Aktionen erstellen, die Sie als solche übergeben.

internal class Foo 
{ 
    private bool FooIsEnabled; 

    public void Bar() 
    { 
     Execute(() => Debug.WriteLine("Bar")); 
    } 

    public void Baz() 
    { 
     Execute(() => Debug.WriteLine("Baz")); 
    } 

    public void Bat() 
    { 
     Execute(() => Debug.WriteLine("Bat")); 
    } 

    public void Execute(Action operation) 
    { 
     if (operation == null) 
      throw new ArgumentNullException("operation"); 

     if (!FooIsEnabled) 
      return; 

     operation.Invoke(); 
    } 
} 
2

Sure:

internal interface IFoo { 
    void Bar(); 
    void Baz(); 
    void Bat(); 
} 

internal class Foo { 
    private IFoo FooImplementation = new DisabledFoo() // or new EnabledFoor() 

    public bool FooIsEnabled 
    { 
     get 
     { 
      return FooImplementation is EnabledFoo; 
     } 
     set 
     { 
      FooImplementation = value ? new EnabledFoo() : new DisabledFoo() 
     } 
    } 

    public void Bar() { 
     FooImplementation.Bar(); 
    } 
    public void Baz() { 
     FooImplementation.Baz(); 
    } 
    public void Bat() { 
     FooImplementation.Bat();   
    } 
} 

internal class EnabledFoo : IFoo { 
    public void Bar() { 
     //... 
    } 
    public void Baz() { 
     //... 
    } 
    public void Bat() { 
     //... 
    } 
} 

internal class DisabledFoo : IFoo { 
    public void Bar() {} 
    public void Baz() {} 
    public void Bat() {} 
} 

Und wenn Ihre Absicht ist es, die foo Implementierung für Unit-Tests zu verspotten, fallen nur die FooIsEnabled Eigenschaft und FooImplementation öffentlich machen. In diesem Fall sollten Sie auch loswerden DisabledFoo bekommen und testen eine Instanz mit wie:

var fooImplementationMock = new Mock<IFoo>(); 
var foo = new Foo { FooImplementation = fooImplementationMock.Object }; 
foo.Bar(); 
fooImplementationMock.Verify(f => f.Bar()); 

gegeben Sie moq verwenden.

Verwandte Themen