C# 将大量方法重载转换为通用方法,即设计问题

C# 将大量方法重载转换为通用方法,即设计问题,c#,design-patterns,generics,C#,Design Patterns,Generics,我正在尝试重构一些以前由其他人完成的代码,因为我觉得这很不实际 这里有一个例子 protected void SetParameterValue(SqlParameter parameter, string parameterValue, bool isNullable) { if ((null == parameterValue || parameterValue == NULL_STRING) && isNullable) parameter

我正在尝试重构一些以前由其他人完成的代码,因为我觉得这很不实际 这里有一个例子

protected void SetParameterValue(SqlParameter parameter, string parameterValue, bool isNullable)
{
     if ((null == parameterValue || parameterValue == NULL_STRING) && isNullable)
            parameter.Value = DBNull.Value;
     else   parameter.Value = parameterValue;
}

protected void SetParameterValue(SqlParameter parameter, int parameterValue, bool isNullable)
{
     if (parameterValue == NULL_INT && isNullable)
            parameter.Value = DBNull.Value;
     else   parameter.Value = parameterValue;
}

protected void SetParameterValue( SqlParameter parameter, Int64 parameterValue, bool isNullable)
{
     if (parameterValue == NULL_LONG && isNullable)
            parameter.Value = DBNull.Value;
     else   parameter.Value = parameterValue;
}
像这些,还有很多。现在我需要创建一个接受新类型(它还没有方法)的,并决定也许我可以清理一下,使它更好。 我的想法是创造一些像

protected void SetParameterValue<T>(SqlParameter parameter, T parameterValue, bool isNullable)
bool IsNull (object value){
   if (value is int){
     check int..
   }
}
//this is a quick and dirty example, there are more elegant ways to handle it.
受保护的void SetParameterValue(SqlParameter参数、T parameterValue、bool可为空)
但是,我不知道什么是最好的方法,我可以在这个通用方法中封装什么,以及在单独的方法中需要做什么。值得吗?还是“多种方法”的方法可以?我会从通用的那个中得到什么?谢谢

你总是可以的

Protected void SetParameterValue(SqlParameter parameter, 
 object parameterValue, bool isNullable)....
parameter.Value
接受一个对象,因此减去每种类型的验证后,您实际上不需要将它们分开

您可以创建一个validate parameter方法,该方法反映并提取参数的类型,并检查是否针对该类型设置了null值。 差不多

protected void SetParameterValue<T>(SqlParameter parameter, T parameterValue, bool isNullable)
bool IsNull (object value){
   if (value is int){
     check int..
   }
}
//this is a quick and dirty example, there are more elegant ways to handle it.

这压缩了类型验证和所有重载,也消除了对泛型方法的需要。

我认为可以使用可空类型,而不是bool isNullable

protected void SetParameterValue<T>(SqlParameter parameter, T parameterValue)
{
if (parameterValue == null)
  parameter.Value = DBNull.Value;
else
  parameter.Value = parameterValue;
}
protectedvoid SetParameterValue(SqlParameter参数,T参数值)
{
如果(参数值==null)
parameter.Value=DBNull.Value;
其他的
parameter.Value=parameterValue;
}
并可能相应地用这个签名来称呼它。 喜欢 SetParameter(参数,null)
SetParameter(param,5)

方法定义的“多重签名”方法非常好——它给了我们多态性。就我个人而言,我更愿意保留这种技术,而不是按照你的建议进行重构

但是,我要做的是用对“master”方法的调用来替换除一个方法之外的所有方法体的重复,从而转换参数:

protected void SetParameterValue(SqlParameter parameter, int parameterValue, bool isNullable)
{
  SetParameterValue(parameter, (Int64)parameterValue, isNullable);
}
protected void SetParameterValue(SqlParameter parameter, Int64 parameterValue, bool isNullable)
{
  if (parameterValue == NULL_INT && isNullable)
    parameter.Value = DBNull.Value;
  else
    parameter.Value = parameterValue;
}
当然,这前提是
parameterValue
可以在没有太多麻烦的情况下重新转换。

很难用switch/if stations“删除”这个问题,如果最后有人不得不这样做。 您可以选择覆盖/封装对象或类的空值,但仍然需要检查每个概念中的空值

我不知道这是否会让事情变得更好,但是您可以首先通过创建一个方法来隔离重复,就像前面所说的,或者只隔离空值检查。最后一个是我所做的:

protected void SetParameterValue(SqlParameter parameter,object parameterValue){
    if(IsParameterNull(parameterValue) && parameter.IsNullable){
        parameter.Value = DBNull.Value;
    }
    else{
        parameter.Value = parameterValue;
    }
}

List<NULLTYPE> nulls = new List<NULLTYPE>(){new NULLTYPE(NULL_INT), new NULLTYPE(NULL_LONG), new NULLTYPE(null)}
protected bool IsParameterNull(object parameterValue){
    if(nulls.Contains(parameterValue)) return true;
    else return false;
}
受保护的void SetParameterValue(SqlParameter参数,对象parameterValue){
if(IsParameterNull(parameterValue)和¶meter.IsNullable){
parameter.Value=DBNull.Value;
}
否则{
parameter.Value=parameterValue;
}
}
List nulls=new List(){new NULLTYPE(NULL_INT)、new NULLTYPE(NULL_LONG)、new NULLTYPE(NULL)}
受保护的bool IsParameterNull(对象参数值){
if(nulls.Contains(parameterValue))返回true;
否则返回false;
}
这里的工作是创建一个
NULLTYPE
类,该类封装了null的概念,并且
nulls.Contains(parameterValue)
检查列表中是否存在该值。
您可以更进一步,覆盖
Contains
以自己的方式进行检查,但您必须考虑在这方面要花费多少工作。

消除开关需求的一种方法是使用某种字典来保存委托,以确定每种可能类型的null构成。尽管我认为你必须坚持使用object。因此,您将拥有一本字典,并将其设置为:

private Dictionary<Type, Func<object, bool, bool>> _nullChecks = new Dictionary<Type, Func<object, bool, bool>>();

private void SetupNullChecks(){
    _nullChecks.Add(typeof(string), (object parameterValue, bool isNullable) => { return (null == parameterValue || parameterValue.ToString() == NULL_STRING) && isNullable; });
    _nullChecks.Add(typeof(int), (object parameterValue, bool isNullable) => { return (int)parameterValue == NULL_INT && isNullable; });
    _nullChecks.Add(typeof(long), (object parameterValue, bool isNullable) => { return (long)parameterValue == NULL_LONG && isNullable; });
}

但是,正如其他人所建议的,改变代码以使用可空类型会更好。

@亚历克斯,现在有一小部分是空的类型,可以考虑删除那些nulLyint,nulLyLon等常数,只使用<代码> int > <代码>,<代码>长> <代码>作为数据类型。问题是NulLIn int,etc在很多地方,我想执行一些快速重构,使事情变得更好,而不必更改大量代码(和大量重新测试),但说真的,当int值为0时,您总是设置NULL?您没有解决值类型不能为NULL的事实。等一下,您是指SetParameter(param,NULL)不起作用?是的,但SetParameter不起作用。由于值类型不能为null parameterValue==null将始终为false。@Kevin好吧,但在这种情况下int-parameter将不等于null_-int(有问题)@jenea,除非这不在您的验证逻辑中,否则仍有人可以执行SetParameterValue。。。。并将null值验证为true。有其他选项添加int值并不重要。提供的通用方法允许这种情况发生。我想知道同样的事情。。。我可能也会尝试用Nullable或NULL(如果适用)替换NULL_字符串、NULL_INT等。我认为传递“对象”类型不是一个好的做法,而且有很多装箱/取消装箱。泛型不是可以完成同样的任务,但不必为每种类型创建一个巨大的switch语句吗?您仍然要使用box,因为parameter.Value接受一个对象。条件语句将很难绕过,因为您最终将不得不询问“这个对象是什么类型的?“当你得到答案时,你已经制定了某些验证规则。如果这是X,那么就这样做。这完全取决于你要问问题的地方,在你的例子中,你仍然在做,你只是把方法之间的逻辑分开了。我忘了说的另一件事是,如果你真的想编写一个好的代码,从阅读干净的代码开始。这不是一本圣经,我也不是一个福音传道者,但它会开阔你的思路,或者至少对你有一点帮助。这似乎是一个有趣的解决方案,尽管我不确定我是否理解NULLTYPE类是什么样子。怎么办