如何在 C# 中创建 Fluent Interface 并对某些方法有一些限制?

How create Fluent Interface in C# with some limitation for some methods?

查看以下代码:

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

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

所以没有人可以写这样的代码:

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

我想限制某些方法可以接受特殊方法等。 我可以将所有方法写在一个 class 和 return 中,但这是不合适的!!!

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

要限制事物,您需要创建和 return 一个(可能是几个)"builder" 可以执行特殊操作的对象,并保持对主要 class 的引用。

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

使用内部访问限制使用。

为了避免产生垃圾,在 main class

中存储一个 SubConditionCreator 引用

考虑返回一个仅包含 And()Or() 的接口。例如:

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

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

据我所知,没有真正简单的方法可以解决这个问题。或许 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 中实现这些:

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

你 return this Add() And() Or() 并保持这些状态变化和顺序。

我希望有人用手动写出每个节点的更好方法来回答这个问题。

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

这似乎有效。

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