在不更改类的情况下更改一个方法的行为的最简单方法
本文关键字:方法 一个 最简单 情况下 | 更新日期: 2023-09-27 18:08:31
一点背景:我使用IQToolkit编写一个使用System.Data.Odbc
而不是System.Data.SqlClient
的自定义数据提供程序。
我遇到了默认参数器类的问题,在这里找到。下面的代码片段是我需要修改的,总共只有一个方法。
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;
}
我想了好几种方法来完成这个任务,但是我都不喜欢。
我有源代码,所以我可以改变源代码本身并重新编译它。但是,这将为其他SQL方言删除一些有用的代码,我不想仅仅为了ODBC而破坏这一切。
我可以写我自己的
Parameterizer
类,并使用它而不是默认的。如果我这样做,我将复制250行代码,只是为了改变三到四行。我可以尝试重写类,只改变我需要的方法。我试过了,但是我在
Parameterizer
类的保护水平上遇到了一些问题。我最喜欢这个,但我不确定我做得很正确,或者如果我甚至可以用给定的类设计。
道歉,如果问题似乎模糊,但有没有任何简单的方法让我改变该方法的行为,而不必改变基类或不复制其所有的代码?
EDIT:问题#3:不能访问IsNumeric
(私有Parameterizer
),不能访问Parameterizer.map
,不能访问TypeAndValue
结构体,不能访问Parameterizer.language
这就是我的想法(基于我们的评论)。
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;
}
}
访客,访客模式…
"从本质上讲,访问器允许一个人给a添加新的虚拟功能不修改类本身的类族"
。这意味着在大多数情况下,这本身就足够了,不需要求助于继承和重写(这有点多余,有点简化)。您可以使用这个事实来覆盖原始访问者的某些行为(因为您已经有了适当的机制),从而避免继承和可能出现的问题。
唯一可能的问题是-
Parameterizer
没有默认的行为-我认为这是不可能的可能无论如何都需要。
最终重写参数器更容易。不确定这是否广泛相关,但我必须更改代码,以防有人感兴趣:
这个方法的问题是,它试图重用具有重复类型和值的参数。但是,由于我使用的是未命名的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
构造函数,使参数的哈希值唯一,即使它们的类型和值相同。我通过添加参数number来实现这一点。
public TypeAndValue(Type type, object value, int pCount)
{
this.type = type;
this.value = value;
this.hash = type.GetHashCode() + (value != null ? value.GetHashCode() : 0) + pCount;
}