Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call multiple method with same out and different input in loop

I have multiple methods with different input parameters and same outputs.

I call Method1 with input type of number and then check its result, if the result is valid next method gets called ( this time with input type of string) and so on.

In this example i have three methods, but if i have 10 methods or 20 methods with different inputs and same outputs i have to write redundant code, how can i prevent these redundant codes?

this is sample of methods:

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;
}

And i call this methods as following:

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();
}
like image 768
Mohammad Akbari Avatar asked Dec 11 '16 12:12

Mohammad Akbari


Video Answer


4 Answers

(also check alternate solution below!)

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

This comes, however, with some performance penalty for the delegates, and since you need the parameters, it's hard to place outside, e.g. in a method returning the delegates.

As an alternative, you could create a values bag as parameter (might be your calling class with a proper interface), which is the same for all methods, and each method picks what it needs (which, in turn, makes the validation methods less clear).

Another alternative would be to just return bool values and keep the validation details in separate objects, possibly implementing extension methods for validation (also check Myleo's predicates answer):

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 ...
    }
}

then, in validating code:

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

This way, you'll not have to mess with delegates. The checks stop when the first fails (|| or condition checks stop on first success, here a negated IsValid). And your valResults still contain the validation data.

From your code, it might also be feasible to simply use exceptions. Such exception-less validation may be necessary if errors occur frequently, and exceptions kill performace, but if errors are exceptional, then feel free to use an exception!

like image 129
Erik Hart Avatar answered Oct 21 '22 09:10

Erik Hart


with predicate may be ?

you can do something like

        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;
        }

If you have many parameters. This is not the best way but:

        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;
        }
like image 41
Myleo Avatar answered Oct 21 '22 08:10

Myleo


I guess one problem is the method signature, some accepts int, while others accept string..etc; How about create yourself a new type, say InputParam:

public class InputParam {
   private int fieldOne;
   private string fieldTwo;
   ...
   GetFieldOne(); 
   GetFieldTwo();
   ...
}

Then, you could potentially have as many methods as you need, Method1 up to 20. Of course, each method will be responsible of picking up only the fields it needs out of an InputParam instance.

Now, all your methods share the same signature, thus you can have an array of methods and loop against it.

like image 2
Marius M Avatar answered Oct 21 '22 09:10

Marius M


you can use is keyword like this

    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 "...";

    }
like image 1
Ali Sheikh Nezami Avatar answered Oct 21 '22 08:10

Ali Sheikh Nezami