2016-05-30 6 views
9

Ich habe eine C# -Klasse, die virtuelle Operationen bereitstellt. Für jede Operation existiert eine synchrone und eine asynchrone Version.Eine Warnung anzeigen, wenn nur eines der beiden Methoden oder Eigenschaften überschrieben wird

public class Foo{ 
    public virtual void Bar(){..}; 
    public virtual Task BarAsync(){..}; 

    ... 
} 

Ich möchte den Compiler eine Warnung aus, wenn nur eine Version der Operation zeigt, außer Kraft gesetzt wird (die synchrone oder asynchrone Version des Betriebs), wie der Compiler warnt, wenn ein Equals überschreibt ohne GetHashCode zwingende oder und umgekehrt.

Auf breiter Ebene befragt: Ist es möglich zu erzwingen, dass das Überschreiben einer Methode oder Eigenschaft das Überschreiben anderer Eigenschaften oder Methoden erzwingt (über Compilerwarnungen).

+0

Sie würden einen [roslyn Analysator] (https://github.com/dotnet/roslyn-analyzers) zu schreiben. –

+0

Wie HimBromBeere geantwortet hat, scheint es logischer zu sein, einfach eine abstrakte Basisklasse zu erstellen und den tatsächlich vorhandenen Code, der in Ihrem Fall überschrieben würde, in eine bestehende Implementierung zu übernehmen. – Nyerguds

+0

Die Klasse ist ein Teil eines kleinen Frameworks und die vorgeschlagene Architektur verkompliziert ihre Verwendung, da das Konsumieren von Foo nicht auf die gleiche Weise erfolgt wie von Foo. – HCL

Antwort

3

Obwohl dies keine Antwort auf Ihre eigentliche Frage ist, frage ich nach einem Ansatz, bei dem Sie nicht einmal die Warnung brauchen.

Warum nicht eine abstrakte Klassen mit overridable Mitgliedern erstellen und eine versiegelte ohne:

public class Foo{ 
    public virtual void Bar(){..} 
    public virtual Task BarAsync(){..} 
} 

public abstract class ImplementIt : Foo { 
    public abstract override void Bar(); 
    public abstract override Task BarAsync(); 
} 
public sealed class DoNotImplementIt : Foo { 
    public override void Bar() {..} 
    public override Task BarAsync() {..} 
} 

Jetzt können Client entwerfen, wenn er eine Implementierung von Foo whith Ihr Standardverhalten (= DoNotImplementIt) muss oder wenn er einen anpassbaren braucht Version mit ImplementIt. Im ersteren Fall ist er gezwungen, die Mitglieder in letzterem Fall außer Kraft zu setzen.

Dieser Ansatz ist für Ihren API-Benutzer viel sauberer, da er weiß, was er aus der Vererbungskette entfernen muss, anstatt sich auf unordentliche Warnungen zu verlassen, um die sich niemand kümmert.

Ein noch besserer Ansatz Foo als Schnittstelle zu definieren wäre, die sowohl ImplementIt und DoNotImplementIt implementieren (klingt komisch, aber bekommen Sie es). Speichert Sie von diesem abstract override. Auf diese Weise können Sie auch Ihre Schnittstelle von außen verbergen, indem Sie sie internal machen und nur die implementierenden Klassen über die API zugänglich machen.

+0

Sie meinen, die abstrakte Klasse stammt aus der ersten Klasse?Es gibt Probleme mit der Zugänglichkeit ("public") und mit Benennung ("Bar" kann keine Methode einer Klasse "Bar" sein). –

+0

@JeppeStigNielsen Yeap, ich habe Vorrang vor 'Foo'-Klasse. Ich habe auch die Namen der Mitglieder geändert. – HimBromBeere

+0

Das half, aber Sie haben immer noch ein Problem damit, dass die abgeleitete Klasse 'Bar'' public' ist, während ihre Basisklasse nicht. –

0

Sie könnten eine custom Code Analyzer schreiben. Ich habe es nie selbst benutzt. Wir haben FxCop benutzt und ein paar Regeln dafür geschrieben. Aber es ist ziemlich schwierig. Mit Roslyn sollte das viel einfacher sein.

1

Code schreiben, der die gleiche Wirkung wie die Durchsetzung hat.

  • Erstellen Sie eine Schnittstelle mit den Methoden/Eigenschaften, die Sie überschreiben möchten.
  • Schreiben Sie eine (überschreibbare) Funktion, die die Schnittstelle zurückgibt.
  • Also, wenn das überschrieben wird, werden alle Funktionen auf einmal ersetzt.

Beispiel:

public interface IBarMethods 
{ 
    void Bar(); 
    Task BarAsync(); 
} 

public class Foo 
{ 
    public virtual IBarMethods DeMethods() 
    { 
     // return class containing default methods. 
    } 
} 

public class ImplementIt : Foo 
{ 
    public override IBarMethods DeMethods() 
    { 
     // return different methods. 
    }  
} 
+1

Wenn Sie dies tun, kann 'Foo' sogar eine (versiegelte) Methode' Bar' und eine (versiegelte) Methode 'BarAsync' haben, die nur dieses' IBarMethod' Objekt erhalten und die entsprechende Methode aufrufen. Allerdings würde ich wahrscheinlich eher eine Eigenschaft als eine Methode verwenden, um die 'IBarMethods'-Instanz zu erhalten (in meinem Fall eine 'geschützte' Instanz). – Servy

Verwandte Themen