2016-04-26 3 views
8

unten Codes Siehe:Wie erstelle ich eine fließende Oberfläche in C# mit einigen Einschränkungen für einige Methoden?

new ConditionCreator() 
     .Add() 
      .Or() 
     .Add() 
      .And() 
     .Add() 

Ich möchte für diese ein Fluent Interface erstellen Aber ich brauche, nach Methode Add() Entwickler sehen Nur Or() oder und() und nach einer von diesen , siehe nur Add() - Methode.

so kann niemand einen Code wie schreiben:

new ConditionCreator() 
      .Add() 
      .Add() 
      .Add() 
      .Or() 
      .And() 
      .Add() 
      .And() 
      .And() 

möchte ich eine Einschränkung haben für einige Methoden spezielle Methoden nicht annehmen können und etc. ich alle Methoden in einer Klasse schreiben kann, und gibt diese für jeden aber das ist nicht geeignet !!!

Bitte führen Sie mich Wie schreiben Advanced Fluent Interface-Klasse.

+1

Werfen Sie einen Blick auf Code-Basis für FluentAssertions: https://github.com/dennisdoomen/FluentAssertions sie könnten habe schon was du brauchst. – trailmax

+1

Ihre angenommene Antwort kann immer noch "new ConditionCreator() .Add(). Or oder(). Und(). Und(). Und()". Ist es das, was du wolltest oder habe ich deine Frage missverstanden? – Nkosi

+0

Siehe meine aktualisierte Antwort für mehr Details, wie man das richtig löst. – Macke

Antwort

1

Betrachten wir eine Schnittstelle Rückkehr, die nur And() und Or() enthält. Zum Beispiel:

public class ConditionCreator : IFluentAndOr 
{ 
    public IFluentAndOr And() { ... } 
    public IFluentAndOr Or() { ... } 
} 

public interface IFluentAndOr 
{ 
    IFluentAndOr And(); 
    IFluentAndOr Or(); 
} 
+4

Wie löst das die Frage? –

3

Um Dinge einzuschränken, müssen Sie ein (möglicherweise mehrere) "Builder" -Objekte erstellen und zurückgeben, die spezielle Operationen ausführen können, wobei ein Verweis auf die Hauptklasse beibehalten wird.

public class ConditionCreator 
{ 
    public ConditionCreator() { ... } 

    public SubConditionCreator Add() { ...; return new SubConditionCreator(this); } 

    internal ConditionCreator OnAdd() { ...; return this; }; 
    internal ConditionCreator OnOr() { ...; return this; }; 
} 

public class SubConditionCreator 
{ 
    private ConditionCreator _creator; 

    internal SubConditionCreator(ConditionCreator c) { _creator = c; } 

    public ConditionCreator And() { return _creator.OnAdd(); } 
    public ConditionCreator Or() { return _creator.OnOr(); } 
} 

Verwenden Sie den internen Zugriff Nutzung zu beschränken.

Schaffung Müll zu vermeiden, speichern Sie eine SubConditionCreator ref in Hauptklasse

2

Es gibt keine wirklich einfache Möglichkeit, die ich kenne, um dies zu lösen. Vielleicht hilft T4 Templating, aber bisher musste ich immer den Entscheidungsbaum mit einer expliziten Schnittstelle an jedem Knoten aufbauen. Beispielsweise; nehmen wir an, Ihr Entscheidungsbaum ist eine Endlosschleife, dann (entsprechend implementiert):

interface IStart<T> 
{ 
    IAndOr Add(); 
    T End(); 
} 
interface IAndOr<T> 
{ 
    IStart<T> And(); 
    IStart<T> Or(); 
} 

Es wird schwierig, wenn Sie eine endliche Schleife wollen; sagen null bis zwei Adds:

interface IStart<T> : IFinish<T> 
{ 
    IAndOrFirst<T> Add(); 
} 

interface IAndOrFirst<T> 
{ 
    ISecond<T> And(); 
    ISecond<T> Or(); 
} 

interface ISecond<T> : IFinish<T> 
{ 
    IAndOrSecond<T> Add(); 
} 

interface IAndOrSecond <T> 
{ 
    IFinish<T> And(); 
    IFinish<T> Or(); 
}  
interface IFinish<T> 
{  
    T End(); 
} 

Sie können (explizit) setzen diese in einer einzigen Klasse, die als Zustandsmaschine wirkt:

class ConditionCreator <T> : IStart<T>, IFinish<T>, IAndOrFirst<T>, IAndOrSecond<T> {...} 

wo Sie this für Add()And()Or() zurückkehren würde und pflegen diese Zustandsänderungen und -ordnungen.

Ich hoffe, einige Antworten auf diese Frage mit einem besseren Weg, manuell jeden Knoten zu schreiben.

0
  public class DoEqual 
       { 

       } 
       public interface ICanAddWhereValue 
       { 
        ICanAddWhereOrRun IsEqualTo(object value); 
        ICanAddWhereOrRun IsNotEqualTo(object value); 
        IBothEqual BothEqual (object value); 
       } 

       public interface IBothEqual 
       { 
        DoEqual Excute(); 
       } 


       public interface ICanAddWhereOrRun 
       { 
        ICanAddWhereValue Where(string columnName); 
        bool RunNow(); 
        DoEqual Excute(); 
       } 

      public interface ICanAddCondition 
       { 
        ICanAddWhereValue Where(string columnName); 
        bool AllRows(); 
       } 

     namespace BuildAFluentInterface 
     { 
      public class WhereCondition 
      { 
       public enum ComparisonMethod 
       { 
        EqualTo, 
        NotEqualTo 
       } 

       public string ColumnName { get; private set; } 
       public ComparisonMethod Comparator { get; private set; } 
       public object Value { get; private set; } 

       public WhereCondition(string columnName, ComparisonMethod comparator, object value) 
       { 
        ColumnName = columnName; 
        Comparator = comparator; 
        Value = value; 
       } 
      } 
     } 

    using System.Collections.Generic; 

    namespace BuildAFluentInterface 
    { 
     public class DeleteQueryWithoutGrammar 
     { 
      private readonly string _tableName; 
      private readonly List<WhereCondition> _whereConditions = new List<WhereCondition>(); 

      private string _currentWhereConditionColumn; 

      // Private constructor, to force object instantiation from the fluent method(s) 
      private DeleteQueryWithoutGrammar(string tableName) 
      { 
       _tableName = tableName; 
      } 

      #region Initiating Method(s) 

      public static DeleteQueryWithoutGrammar DeleteRowsFrom(string tableName) 
      { 
       return new DeleteQueryWithoutGrammar(tableName); 
      } 

      #endregion 

      #region Chaining Method(s) 

      public DeleteQueryWithoutGrammar Where(string columnName) 
      { 
       _currentWhereConditionColumn = columnName; 

       return this; 
      } 

      public DeleteQueryWithoutGrammar IsEqualTo(object value) 
      { 
       _whereConditions.Add(new WhereCondition(_currentWhereConditionColumn, WhereCondition.ComparisonMethod.EqualTo, value)); 

       return this; 
      } 

      public DeleteQueryWithoutGrammar IsNotEqualTo(object value) 
      { 
       _whereConditions.Add(new WhereCondition(_currentWhereConditionColumn, WhereCondition.ComparisonMethod.NotEqualTo, value)); 

       return this; 
      } 

      #endregion 

      #region Executing Method(s) 

      public void AllRows() 
      { 
       ExecuteThisQuery(); 
      } 

      public void RunNow() 
      { 
       ExecuteThisQuery(); 
      } 

      #endregion 

      private void ExecuteThisQuery() 
      { 
       // Code to build and execute the delete query 
      } 
     } 
    } 
<br> 
In Main Test with 
public class myclass 
{ 
private static void Main(string[] args) 
     { 
DoEqual x3 = 
       DeleteQueryWithGrammar.DeleteRowsFrom("Account") 
        .Where("Admin") 
        .IsNotEqualTo("Admin") 
        .Where("Admin") 
        .BothEqual("X") 
        .Excute(); 
} 
} 
0

Dies scheint zu funktionieren.

public class ConditionCreator 
    { 
    private Decision decision; 

    public ConditionCreator() { decision = new Decision(this); } 
    public Decision Add() { return decision; } 

    public class Decision 
    { 
     private ConditionCreator creator; 

     public Decision(ConditionCreator creator) { this.creator = creator; } 
     public ConditionCreator And() { return creator; } 
     public ConditionCreator Or() { return creator; } 
     public Condition Create() { return new Condition(); } 
    } 
    } 

Und Sie sind jetzt auf Muster wie diese beschränkt, wenn Sie die Anrufe zu tätigen:

 var condition = new ConditionCreator() 
     .Add() 
     .Or() 
     .Add() 
     .And() 
     .Add() 
     .Create(); 
+0

Jetzt ist mir klar, das ist sehr ähnlich wie @ Mackes Antwort. Naja... –

Verwandte Themen