如何在C#中创建Fluent接口,对某些方法有一些限制?

时间:2016-04-26 10:17:53

标签: c# fluent-interface method-chaining

见以下代码:

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

我想为此创建一个Fluent界面 但是我需要, 在Add()方法开发人员之后看到只有Or()或And() 和 在其中一个之后,请参阅Only Add()方法。

所以没有人可以编写如下代码:

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

我想对某些方法有限制可以接受特殊方法等。 我可以在一个类中编写所有方法并为每个方法返回这个方法,但这不合适!!!

请指导我如何编写Advanced Fluent Interface类。

5 个答案:

答案 0 :(得分:4)

要限制事物,你需要创建并返回一个(可能是几个)" builder"可以执行特殊操作的对象,保留对主类的引用。

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

使用内部访问来限制使用。

为避免产生垃圾,请在主类中存储SubConditionCreator参考

答案 1 :(得分:2)

我不知道解决这个问题的真正方法。也许T4模板可能有所帮助,但到目前为止,我总是不得不建立决策树,每个节点都有一个显式接口。例如;假设你的决策树是一个无限循环,然后(相应地实现):

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

如果你想要一个有限的循环,那就很难了;说零到两个添加:

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

您可以(明确地)在充当状态机的单个类中实现这些:

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

您要为this Add() And()返回Or(),并维护这些状态更改和订单。

我希望能够以更好的方式手动写出每个节点来回答这个问题。

答案 2 :(得分:0)

考虑返回仅包含And()Or()的界面。例如:

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

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

答案 3 :(得分: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();
}
}

答案 4 :(得分:0)

这似乎有效。

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

现在,当你拨打电话时,你现在被限制在这样的模式中:

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