2016-04-26 1 views
8

Voir ci-dessous les codes:Comment créer une interface fluide en C# avec certaines limitations pour certaines méthodes?

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

Je veux créer une interface Fluent pour que Mais j'ai besoin, après développeur de méthode Add() Voir seulement Ou() Untel ou() et après l'un de ces , voir la méthode Only Add().

afin que personne ne peut écrire un code comme:

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

Je veux avoir une limitation de certaines méthodes peuvent accepter des méthodes spéciales, etc Je peux écrire toutes les méthodes dans une classe et retourner ce pour chaque un mais ce n'est pas approprié !!!

S'il vous plaît guidez-moi Comment écrire classe Advanced Fluent Interface.

+1

un coup d'oeil sur base de code pour FluentAssertions: ils pourraient https://github.com/dennisdoomen/FluentAssertions avez déjà ce dont vous avez besoin. – trailmax

+1

Votre réponse acceptée peut toujours permettre 'new ConditionCreator() .Add(). Ou(). Et(). Et(). Et()'. Est-ce ce que vous vouliez ou ai-je mal compris votre question. – Nkosi

+0

Voir ma réponse mise à jour pour plus de détails sur la façon de résoudre cela correctement. – Macke

Répondre

1

retour d'une interface Tenir compte qui ne contient que And() et Or(). Par exemple:

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

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

comment cela résout-il la question? –

3

Pour limiter les choses, vous devez créer et renvoyer un (parmi plusieurs) objets "constructeur" pouvant effectuer des opérations spéciales, en gardant une référence à la classe principale.

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(); } 
} 

Utilisez l'accès interne pour restreindre l'utilisation.

Pour éviter de créer des ordures, stocker une ref SubConditionCreator dans la classe principale

2

Il n'y a pas vraiment de solution simple pour résoudre ce problème. Peut-être que la modélisation T4 peut aider, mais jusqu'à présent, j'ai toujours dû construire l'arbre de décision, avec une interface explicite à chaque nœud. Par exemple; permet d'assumer votre arbre de décision est une boucle infinie, puis (mis en œuvre en conséquence):

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

Il devient difficile si vous voulez une boucle finie; dire zéro à deux 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(); 
} 

Vous pouvez (explicitement) mettre en œuvre ces derniers dans une seule classe qui agit comme la machine d'état:

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

où vous rentrerais this pour Add()And()Or() et maintenir ces changements d'état et l'ordre.

J'espère que certains répondra à cette question avec une meilleure façon d'écrire manuellement chaque nœud.

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

Cela semble fonctionner.

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(); } 
    } 
    } 

Et vous êtes maintenant limité à des modèles comme celui-ci lorsque vous effectuez les appels:

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

Maintenant, je me rends compte que c'est très semblable à la réponse de @ Macke. Tant pis... –