0

一点背景知识:我正在使用IQToolkit编写一个自定义数据提供程序,它使用System.Data.Odbc而不是System.Data.SqlClient.

我在此处找到的默认 Parameterizer 类遇到了问题。下面的代码片段是我需要更改的,仅相当于一种方法。

    int iParam = 0;
    protected override Expression VisitConstant(ConstantExpression c)
    {
        if (c.Value != null && !IsNumeric(c.Value.GetType())) {
            NamedValueExpression nv;
            TypeAndValue tv = new TypeAndValue(c.Type, c.Value);
            if (!this.map.TryGetValue(tv, out nv)) { // re-use same name-value if same type & value
                string name = "p" + (iParam++);
                nv = new NamedValueExpression(name, this.language.TypeSystem.GetColumnType(c.Type), c);
                this.map.Add(tv, nv);
            }
            return nv;
        }
        return c;
    }

我已经想到了几种方法可以做到这一点,但我真的不喜欢其中任何一种。

  1. 我有源代码,所以我可以更改源代码本身并重新编译它。但是,这会为其他 SQL 方言删除一些有用的代码,我不想仅仅为了 ODBC 而破坏这一切。

  2. 我可以编写自己的Parameterizer类并使用它而不是默认值。如果我这样做,我将复制 250 行代码以更改三四行。

  3. 我可以尝试重写该类,只更改我需要的方法。我试过这个,但我在课堂上的保护级别遇到了一些问题Parameterizer。我最喜欢这个,但我不确定我做得是否正确,或者如果我什至可以使用给定的类设计。

如果问题看起来含糊不清,请道歉,但是有什么简单的方法可以让我改变该方法的行为,而无需更改基类或复制其所有代码?

编辑:#3 的问题:不能访问IsNumeric(私有Parameterizer),不能访问Parameterizer.map,不能访问 struct TypeAndValue,不能访问Parameterizer.language

4

2 回答 2

2

例如,我的想法是这样的(基于我们的评论)。

public class MyVisitor : DbExpressionVisitor
{
    // cast it to the visitor interface/base - that way you'd have access to all methods,
    // as Parameterizer has to have them publically exposed anyway, for this to work
    readonly DbExpressionVisitor _defaultVisitor;
    public MyVisitor()
    {
        _defaultVisitor = new Parameterizer();
    }
    public Expression VisitProjection(ProjectionExpression proj)
    {
        return _defaultVisitor.Visit(proj);
    }
    // ...same for all others, just...
    // ... 

    // implement your own for one 'route'
    protected Expression VisitConstant(ConstantExpression c)
    {
        if (c.Value != null && !IsNumeric(c.Value.GetType())) {
            NamedValueExpression nv;
            TypeAndValue tv = new TypeAndValue(c.Type, c.Value);
            if (!this.map.TryGetValue(tv, out nv)) { // re-use same name-value if same type & value
                string name = "p" + (iParam++);
                nv = new NamedValueExpression(name, this.language.TypeSystem.GetColumnType(c.Type), c);
                this.map.Add(tv, nv);
            }
            return nv;
        }
        return c;
    }
}

访客,访客模式...

“本质上,访问者允许在不修改类本身的情况下将新的虚函数添加到类族中”

即,这意味着在大多数情况下,这本身就足够了,无需求助于继承、覆盖(这有点多余,有点简化)。您可以使用该事实来覆盖原始访问者的某些行为(因为您已经有一个机制) - 并避免继承和您可能遇到的问题。

唯一可能的问题可能是 -Parameterizer 没有默认的ctor - 我认为这不太可能,因为你可能需要这样做。

于 2013-04-09T18:38:06.097 回答
0

它最终只是更容易重写参数化程序。不确定这是否具有广泛的相关性,但我必须更改代码,以防有人感兴趣:

此方法的问题在于它试图重用具有重复类型和值的参数。但是,由于我使用的是未命名的 ODBC 样式参数,因此查询必须具有与查询指定的参数数量相同的参数,即使它们完全相同。

protected override Expression VisitConstant(ConstantExpression c)
{
    if (c.Value != null && !IsNumeric(c.Value.GetType())) {
        NamedValueExpression nv;
        TypeAndValue tv = new TypeAndValue(c.Type, c.Value, iParam);

        string name = "p" + (iParam++);
        nv = new NamedValueExpression(name, this.language.TypeSystem.GetColumnType(c.Type), c);
        this.map.Add(tv, nv);

        return nv;
    }
    return c;
}

我还必须修改TypeAndValue构造函数以使参数的哈希值唯一,即使它们的类型和值相同。我通过添加参数号来做到这一点。

public TypeAndValue(Type type, object value, int pCount)
{
    this.type = type;
    this.value = value;
    this.hash = type.GetHashCode() + (value != null ? value.GetHashCode() : 0) + pCount;
}
于 2013-04-11T12:23:36.723 回答