0

Ich habe eine Klassenbibliothek, die den Befehlszeilenclient für Mercurial umschließt.Wie erstellt man eine erweiterbare API und verwendet weiterhin die Syntax der Objektinitialisierer?

Meine Absicht ist es, Unterstützung für alle eingebauten Befehle zu implementieren, aber zusätzlich zu diesen gibt es eine Tonne von Erweiterungen da draußen.

Also muss ich meine Bibliothek erweiterbar in dem Sinne, dass sowohl andere als auch ich Unterstützung für Erweiterungen hinzufügen können. Ich plane, Unterstützung für einige der populäreren und typischen Erweiterungen hinzuzufügen (zumindest einige von denen, die mit Mercurial geliefert werden), aber ich möchte immer noch in der Lage sein, es von außen zu erweitern.

Im Moment ist die Syntax eines Befehls dies wie folgt aussehen:

Repo.Execute(new CommitCommand 
{ 
    Message = "Your commit message", 
    AddRemove = true, 
}); 

Dies ist jedoch selbst zu Erweiterungen, ohne den Programmierer sehr leicht ist das Gefühl nicht verleihen, dass die Verlängerung nur geheftet Teil.

Zum Beispiel nehmen wir an, ich eine öffentliche Sammlung von zusätzlichen Befehlszeilenargumente aussetzen, zu, dass ich manuell dies tun könnte:

var cmd = new CommitCommand 
{ 
    Message = "Your commit message", 
    AddRemove = true, 
}; 
cmd.Arguments.Add("--my-commit-extension"); 
Repo.Execute(cmd); 

Es scheint keine einfache Art und Weise zu sein, für mich, dass zusätzliche Erweiterung zu bekommen hinzugefügt so dass es als Teil des Objektinitialisierers gesetzt werden kann.

Ich habe darüber nachgedacht, eine fließende Schnittstellensyntax hinzuzufügen oder vielleicht zu wechseln. In diesem Fall könnten Sie so etwas schreiben:

Repo.Execute(new CommitCommand() 
    .Message("Your commit message") 
    .AddRemove() 
    .MyCommitExtension()); 

Allerdings sehe ich die Menschen nicht wie fließend Schnittstellen, sie fühlen sich zu gesprächig geworden.

Welche anderen Optionen habe ich?

Was ich will, im Grunde:

  • Eine gemeinsame Syntax Stil
    • Für beide Einbau in Sachen
    • sowie Erweiterungen von Nutzern meiner Bibliothek hinzugefügt

Ich stelle mir vor, dass Benutzer meiner Bibliothek es erweitern würden, indem sie neue Klassen und Erweiterungsmethoden hinzufügen t Intellisense-Unterstützung, aber Erweiterungsmethoden können nicht in Objektinitialisierern verwendet werden, was bedeutet, dass alle Erweiterungen wie ein nachträglicher Einfall aussehen. Das ist nicht was ich will.

Alle Ideen sind willkommen.

Antwort

1

Ich bin nicht mit Mercurial familier und Ihre Frage scheint zu allgemein, speziell zu adressieren, aber ich kann einen bestimmten Kommentar adressieren.

var cmd = new CommitCommand 
{ 
    Message = "Your commit message", 
    AddRemove = true, 
}; 
cmd.Arguments.Add("--my-commit-extension"); 
Repo.Execute(cmd); 

Wenn CommitCommand.Argumente IList<T> Sie haben bereits die Möglichkeit, initializer Syntax:

class CommitCommand 
{ 
    public string Message { get; set; } 
    public bool AddRemove { get; set; } 
    public List<string> Arguments = new List<string>(); 
} 

Repo.Execute(new CommitCommand 
{ 
    Message = "Your commit message", 
    AddRemove = true, 
    Arguments = { "--my-commit-extension", "--my-other-commit-extension" } 
}); 
+0

Ja, aber sorry, mein Fehler, ich vereinfachte . Ich beabsichtige, normale Methoden zu haben, so dass der Programmierer, der die Bibliothek + die Erweiterungen verwendet, die tatsächlichen Argumente nicht kennen muss. –

+0

Klingt wie eine gute Verwendung für die Dynamik. – Tergiver

1

Auch ich bin nicht so vertraut mit Mercurial, aber eine Option ist Intellisense zu werfen und anonyme Typen verwenden:

Repo.Execute(new 
{ 
    Message = "Your commit message", 
    AddRemove = true, 
    MyCommitExtension = null 
}); 

Sie Bindestriche in Eigenschaftsnamen können nicht verwendet werden, daher müssen Sie von PascalCase zu Bindestrich-Kleinbuchstaben wechseln. Alternativ könnten Sie Unterstriche nur durch Hyphen ersetzen.

Ich bin mir nicht sicher, ich würde empfehlen dieser Ansatz, ohne mehr über die Häufigkeit zu wissen, mit der Menschen diese Erweiterungen verwenden werden. Dieser Ansatz funktioniert im ASP.NET-MVC-Framework gut, wenn es um HTML-Attribute geht. Dieses Szenario unterscheidet sich jedoch dadurch, dass das Framework die Werte nicht verarbeiten muss, sondern direkt in die Ausgabe schreibt. Wenn Sie bedingte Aktionen basierend auf den auf diese Weise bereitgestellten Werten ausführen oder wenn Ihre API für diejenigen, die die Befehlszeilensyntax von Mercurial nicht kennen, leichter gefunden werden kann, können Sie einen anderen Ansatz versuchen.

0

Wie für mich fließend Schnittstelle ist in Ordnung. Aber wenn Sie es vermeiden wollen, dann würde ich wahrscheinlich smth wie folgt verwenden:

interface IExtension { ... } 

class SomeExtension1 : IExtension { ... } 
class SomeExtension2 : IExtension { ... } 

class CommitCommand 
{ 
    public string Message; 
    public bool AddRemove; 
    public readonly IList<IExtension> Extensions = new List<IExtension>(); 
} 

Es ermöglicht auf diese Weise Befehle zu verwenden:

new CommitCommand 
{ 
    Message = "", 
    AddRemove = true, 
    Extensions = {new SomeExtension1(), new SomeExtension2()} 
}; 
Verwandte Themen