在循环中调用具有相同输出和不同输入的多个方法

时间:2016-12-11 12:02:08

标签: c# design-patterns

我有多种方法,输入参数不同,输出相同。

我使用输入类型的数字调用Method1,然后检查其结果,如果结果有效则调用下一个方法(此时输入类型为字符串),依此类推。

在这个例子中,我有三种方法,但如果我有10种方法或20种方法,不同的输入和相同的输出,我必须写冗余代码,我该如何防止这些冗余代码?

这是方法的示例:

public ValidationResult Method1(int number, string family)
{
    var validationResult = new validationResult();
    if(number > 10 || family="akbari")
    {
        validationResult.Errors.Add(new ValidationFailure("", "Invalid Number"));
    }
    return validationResult;
}

public ValidationResult Method1(string name)
{
    var validationResult = new validationResult();
    if(name.Length > 20)
    {
        validationResult.Errors.Add(new ValidationFailure("", "Invalid name"));
    }
    return validationResult;
}

public ValidationResult Method1(double average, string family)
{
    var validationResult = new validationResult();
    if(average < 14)
    {
        validationResult.Errors.Add(new ValidationFailure("", "Invalid average"));
    }
    return validationResult;
}

我称之为以下方法:

var validationResult = Method1(20, "test");
if (!validationResult.IsValid)
{
    return validationResult.FirstError();
}
validationResult = Method2("Samsung");
if (!validationResult.IsValid)
{
    return validationResult.FirstError();
}   
validationResult = Method3(15.5);

if (!validationResult.IsValid)
{
    return validationResult.FirstError();
}

4 个答案:

答案 0 :(得分:3)

谓词可能是?

你可以做点什么

        public ValidationResult Method1(string name)
        {
            return Validate(name, (param) => param.Length > 20, "Invalid name");
        }

        public ValidationResult Method1(double average)
        {
            return Validate(average, (param) => param < 14, "Invalid average");
        }

        private ValidationResult Validate<T>(T param, Func<T, bool> predicate, string message)
        {
            var validationResult = new validationResult();
            if (predicate(param))
            {
                validationResult.Errors.Add(new ValidationFailure("", message));
            }
            return validationResult;
        }

如果你有很多参数。这不是最好的方法,但是:

        public ValidationResult Method1(int number, string family)
        {
            return Validate(number > 10 || family == "akbari", "Invalid Number");
        }

        public ValidationResult Method1(string name)
        {
            return Validate(name.Length > 20, "Invalid name");
        }

        public ValidationResult Method1(double average)
        {
            return Validate(average < 14, "Invalid average");
        }

        public ValidationResult Validate(bool predicate, string message)
        {
            var validationResult = new validationResult();
            if (predicate)
            {
                validationResult.Errors.Add(new ValidationFailure("", message));
            }
            return validationResult;
        }

答案 1 :(得分:3)

(另请查看以下备用解决方案!)

var valMethods = new List<Func<ValidationResult>>
{
    ()=>Method1(number,family),
    ()=>Method2(name),
    // ...
};

foeach(var valMethod in valMethods)
{
    var valResult = valMethod();
    if (!valResult.IsValid)
    {
        return valResult.Errors.First();
    }
}
然而,这会给代表带来一些性能损失,并且由于你需要参数,所以很难放在外面,例如:在一个返回代表的方法中。

作为替代方案,您可以创建一个值包作为参数(可能是具有适当接口的调用类),这对于所有方法都是相同的,并且每个方法都会选择它所需要的(反过来,它会使得验证方法不太清楚)。

另一种选择是返回bool值并将验证细节保存在单独的对象中,可能实现验证的扩展方法(也检查Myleo的谓词答案):

internal static class ValidationMethods
{
    public static bool CheckIsValid1(this IList<ValidationResult> valResults, int number, string family)
    {
        var validationResult = new validationResult();
        if(number > 10 || family="akbari")
        {
            validationResult.Errors.Add(new ValidationFailure("", "Invalid Number"));
        }
        valResults.Add(validationResult);
        return validationResult.IsValid;
    }

    public static bool CheckIsValid2(this IList<ValidationResult> valResults, string name)
    {
        // next check ...
    }
}

然后,在验证代码时:

var valResults = new List<ValidationResult>();
if (!valResults.CheckIsValid1(number, family)
    || !valResults.CheckIsValid2(name)
    || // more checks... will stop if one fails
    )
{
    return valResults.Last().Errors.First();
}

这样,您就不必与代表混淆了。当第一次失败时检查停止(||或条件检查在第一次成功时停止,这里是否定的IsValid)。您的valResults仍包含验证数据。

从您的代码中,简单地使用异常也是可行的。如果错误频繁发生,则可能需要进行此类无异常验证,异常会导致性能下降,但如果错误异常,则可以随意使用异常!

答案 2 :(得分:2)

我猜一个问题是方法签名,一些接受int,而另一些接受string..etc;如何创建一个新类型,比如InputParam:

B = mk.Banana(0.99)

然后,您可能拥有所需数量的方法,Method1最多可达20.当然,每个方法都只负责从InputParam实例中仅选取所需的字段。

现在,您的所有方法共享相同的签名,因此您可以拥有一组方法并对其进行循环。

答案 3 :(得分:1)

您可以使用 这样的

关键字

    static void Main(string[] args)
    {
        Console.WriteLine(@"
        Method1(1)-> return {0};
        Method1('1')-> return {1};
        Method1(0.1)->-> return {2};"
      , Method1(1),
        Method1("1"),
        Method1(0.1));

        Console.WriteLine(@"
        AvgMethod()-> return {0};
        AvgMethod(1)-> return {1};
        AvgMethod('1')-> return {2};
        AvgMethod(0.1)-> return {3};"
        , AvgMethod()
        , AvgMethod(1)
        , AvgMethod("1")
        , AvgMethod(0.1));

        Console.ReadLine();
    }

    public static string Method1(int number)
    {
        return "int";
    }

    public static string Method1(string name)
    {
        return "string";
    }

    public static string Method1(double average)
    {
        return "double";
    }

    public static string AvgMethod(object _argument = null)
    {
        if (_argument is int)
            return "int";
        if (_argument is string)
            return "string";
        if (_argument is double)
            return "double";

        return "...";

    }