如何在 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();
查看以下代码:
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();