c# 将方法限制为其他方法
c# restrict methods to other methods
我有一个 class,其中包含多种方法,例如:
class mySqlTool{
private string _values, _table, _condition, _result;
public mySqlTool Select(string values = null){
//this is REQUIRED
_values = string.Format("select {0} ", values);
return this;
}
public mySqlTool Update(string table){
//this is REQUIRED
_table = table;
return this;
}
public mySqlTool Set(string name, String value){
//this is REQUIRED
//handle name and value
return this;
}
public mySqlTool From(string table = null){
//this is REQUIRED
_table = table;
return this;
}
public mySqlTool Where(string condition = null){
//this is OPTIONAL
_condition = condition;
return this;
}
public string Execute(){
//this is REQUIRED
//this is samplecode, of course here is checked if its select or update
//but to keep it short i erased it
statement = string.Format("{0} {1}", _values, _table);
if (!string.IsNullOrEmpty(_condition))
{
statement += string.Format(" where {0}", _condition);
}
//do some with statemen and fill result
return _result;
}
}
现在我以这种链接方式使用它:
MySqlTool t = new MySqlTool();
string result = t.Select("a,b,c").From("x").Where("foo=bar").Execute();
当我点击 DOT 时,我的 VS 为我提供了可用的方法 (.)
。
我的问题是,我想在使用其他方法之前拒绝使用某些方法,例如:
MySqlTool.Where().Select().From().Execute();
在这种情况下,在调用 .A()
之前,不应调用 .C()
。所以为了澄清什么是允许的,什么是不允许的,这里有一个小列表
//Allowed
t.Select().From().Execute();
t.Select().From().Where().Execute();
t.Update().Set().Set().Set().Where().Where().Where().Execute();
//not Allowed
t.Select().Where().Execute();
t.Select().Select().Select().From().Execute();
t.From()...
t.Where()...
t.Execute()....
我阅读了一些关于接口和状态的内容,但我不确定这是否是我正在寻找的内容。
所以我的问题是:
这可能是我想要的吗?
如果是,这个技术怎么称呼?
一般描述 - 具体评论见文末
Is this what I want even possible?
不在同一个class,不。编译器怎么知道你已经调用了什么? (想象一下你有一个参数类型为 Test
的方法 - 应该可以调用哪些方法?)类型系统决定什么是有效的,什么不是 - 所以如果有不同的有效操作集,这表明不同类型。
您可以做的是使用代表不同状态的不同类型,这将只包括状态转换的适当方法。所以你可以有这样的东西:
class Test0 // Initial state
{
public Test1 A() { ... }
}
class Test1 // After calling A
{
public Test2 B() { ... }
}
class Test2 // After calling B
{
// This returns the same type, so you can call B multiple times
public Test2 B() { ... }
// This returns the same type, so you can call C multiple times
public Test2 C() { ... }
public string DoSomething() { ... }
}
那么你可以使用:
Test0 t = new Test0();
string x1 = t.A().B().DoSome();
string x2 = t.A().B().C().DoSome();
string x3 = t.A().B().B().B().C().C().C().DoSome();
...但是您的无效案例不会编译。
它能用,但它很丑。在不知道这些方法的目的是什么的情况下,很难提出任何其他建议 - 但在许多情况下,带有可选参数的单一方法可能更好,或者可能是构建器模式。
另一种方法是使用单个 class 并在执行时而不是在编译时验证调用。这在编码时帮助不大,但避免了类型的大量混乱。
另一种选择是拥有一个 class - 并创建一个实例 - 但使用接口来表示状态。您的 class 将实现所有接口,因此它仍然可以 return this
:
interface IStart
{
IMiddle A();
}
interface IMiddle
{
IFinal B();
}
interface IFinal
{
IFinal B();
IFinal C();
string DoSomething();
}
class Test : IStart, IMiddle, IFinal
{
public IMiddle A(string x = null) { return this; }
public IFinal B(string x = null) { return this; }
public IFinal C(string x = null) { return this; }
public string DoSomethign { ... }
}
那么您将拥有:
IStart t = new Test();
string x1 = t.A().B().DoSome();
string x2 = t.A().B().C().DoSome();
string x3 = t.A().B().B().B().C().C().C().DoSome();
但这对我来说感觉很不对。我希望 A
、B
和 C
方法能够以某种方式有效地改变状态——因此具有不同的类型将指示哪个状态可用。在第一个示例中,Test0
肯定 没有 具有 A
调用提供的状态,但是 Test1
... 并且 Test2
实例具有 A
和 B
提供的状态,并且可能 C
.
具体例子
对于给出的具体示例,我可能只是让构造函数处理 所需的 信息(table 名称)并使用 properties/indexers其余的部分。我可能会从更新中分离出查询命令:
SqlQuery query = new SqlQuery("table")
{
Columns = { "a", "b", "c" },
Where = { "foo=bar" } // Not sure how you're parameterizing these
};
并且:
SqlUpdate update = new SqlUpdate("table")
{
// Which columns to update with which values
["a"] = 10,
["b"] = 20,
Where = { "foo=bar" } // Not sure how you're parameterizing these
};
在每种情况下,都会有一个 Execute
方法 return 获得适当的结果。
我有一个 class,其中包含多种方法,例如:
class mySqlTool{
private string _values, _table, _condition, _result;
public mySqlTool Select(string values = null){
//this is REQUIRED
_values = string.Format("select {0} ", values);
return this;
}
public mySqlTool Update(string table){
//this is REQUIRED
_table = table;
return this;
}
public mySqlTool Set(string name, String value){
//this is REQUIRED
//handle name and value
return this;
}
public mySqlTool From(string table = null){
//this is REQUIRED
_table = table;
return this;
}
public mySqlTool Where(string condition = null){
//this is OPTIONAL
_condition = condition;
return this;
}
public string Execute(){
//this is REQUIRED
//this is samplecode, of course here is checked if its select or update
//but to keep it short i erased it
statement = string.Format("{0} {1}", _values, _table);
if (!string.IsNullOrEmpty(_condition))
{
statement += string.Format(" where {0}", _condition);
}
//do some with statemen and fill result
return _result;
}
}
现在我以这种链接方式使用它:
MySqlTool t = new MySqlTool();
string result = t.Select("a,b,c").From("x").Where("foo=bar").Execute();
当我点击 DOT 时,我的 VS 为我提供了可用的方法 (.)
。
我的问题是,我想在使用其他方法之前拒绝使用某些方法,例如:
MySqlTool.Where().Select().From().Execute();
在这种情况下,在调用 .A()
之前,不应调用 .C()
。所以为了澄清什么是允许的,什么是不允许的,这里有一个小列表
//Allowed
t.Select().From().Execute();
t.Select().From().Where().Execute();
t.Update().Set().Set().Set().Where().Where().Where().Execute();
//not Allowed
t.Select().Where().Execute();
t.Select().Select().Select().From().Execute();
t.From()...
t.Where()...
t.Execute()....
我阅读了一些关于接口和状态的内容,但我不确定这是否是我正在寻找的内容。
所以我的问题是:
这可能是我想要的吗?
如果是,这个技术怎么称呼?
一般描述 - 具体评论见文末
Is this what I want even possible?
不在同一个class,不。编译器怎么知道你已经调用了什么? (想象一下你有一个参数类型为 Test
的方法 - 应该可以调用哪些方法?)类型系统决定什么是有效的,什么不是 - 所以如果有不同的有效操作集,这表明不同类型。
您可以做的是使用代表不同状态的不同类型,这将只包括状态转换的适当方法。所以你可以有这样的东西:
class Test0 // Initial state
{
public Test1 A() { ... }
}
class Test1 // After calling A
{
public Test2 B() { ... }
}
class Test2 // After calling B
{
// This returns the same type, so you can call B multiple times
public Test2 B() { ... }
// This returns the same type, so you can call C multiple times
public Test2 C() { ... }
public string DoSomething() { ... }
}
那么你可以使用:
Test0 t = new Test0();
string x1 = t.A().B().DoSome();
string x2 = t.A().B().C().DoSome();
string x3 = t.A().B().B().B().C().C().C().DoSome();
...但是您的无效案例不会编译。
它能用,但它很丑。在不知道这些方法的目的是什么的情况下,很难提出任何其他建议 - 但在许多情况下,带有可选参数的单一方法可能更好,或者可能是构建器模式。
另一种方法是使用单个 class 并在执行时而不是在编译时验证调用。这在编码时帮助不大,但避免了类型的大量混乱。
另一种选择是拥有一个 class - 并创建一个实例 - 但使用接口来表示状态。您的 class 将实现所有接口,因此它仍然可以 return this
:
interface IStart
{
IMiddle A();
}
interface IMiddle
{
IFinal B();
}
interface IFinal
{
IFinal B();
IFinal C();
string DoSomething();
}
class Test : IStart, IMiddle, IFinal
{
public IMiddle A(string x = null) { return this; }
public IFinal B(string x = null) { return this; }
public IFinal C(string x = null) { return this; }
public string DoSomethign { ... }
}
那么您将拥有:
IStart t = new Test();
string x1 = t.A().B().DoSome();
string x2 = t.A().B().C().DoSome();
string x3 = t.A().B().B().B().C().C().C().DoSome();
但这对我来说感觉很不对。我希望 A
、B
和 C
方法能够以某种方式有效地改变状态——因此具有不同的类型将指示哪个状态可用。在第一个示例中,Test0
肯定 没有 具有 A
调用提供的状态,但是 Test1
... 并且 Test2
实例具有 A
和 B
提供的状态,并且可能 C
.
具体例子
对于给出的具体示例,我可能只是让构造函数处理 所需的 信息(table 名称)并使用 properties/indexers其余的部分。我可能会从更新中分离出查询命令:
SqlQuery query = new SqlQuery("table")
{
Columns = { "a", "b", "c" },
Where = { "foo=bar" } // Not sure how you're parameterizing these
};
并且:
SqlUpdate update = new SqlUpdate("table")
{
// Which columns to update with which values
["a"] = 10,
["b"] = 20,
Where = { "foo=bar" } // Not sure how you're parameterizing these
};
在每种情况下,都会有一个 Execute
方法 return 获得适当的结果。