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

但这对我来说感觉很不对。我希望 ABC 方法能够以某种方式有效地改变状态——因此具有不同的类型将指示哪个状态可用。在第一个示例中,Test0 肯定 没有 具有 A 调用提供的状态,但是 Test1 ... 并且 Test2 实例具有 AB 提供的状态,并且可能 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 获得适当的结果。