1
\$\begingroup\$

I am trying to build something that will allow us to configure "custom" validation for each customer. So if a customer wants to see a value contain a specific char, be specific length, or equal something else they just add a pre-created option. I wrote something that seems to be very primitive, but works. I would like it to be more dynamic. For instance, I can pass in actual C# code and it will perform that operation on the value input and being compared.

public class Operation
{
    public object value { get; set; }
    public OMagic perform { get; set; }
}

public class Magic
{


    public bool Validate(object val, Operation operation)
    {
        switch (operation.perform)
        {
            case OMagic.Equal:
                return (string)val == (string)operation.value;
            case OMagic.NotEqual:
                return (string)val != (string)operation.value;
            case OMagic.LengthGreaterThan:
                return (int)val < (int)operation.value;
            case OMagic.LengthEqual:
                return (int)val == (int)operation.value;
            case OMagic.LengthLessThan:
                return (int)val > (int)operation.value;
            default:
                return false;
        }
    }
}

public enum OMagic
{
    Equal,
    NotEqual,
    LengthGreaterThan,
    LengthEqual,
    LengthLessThan

}

That is the primitive code, and here are the tests I wrote (using nunit)

[TestFixtureSetUp]
    public void SetupTest()
    {
        //CurrentMessage = getMessage(WebIZ.Test.UnitTest.Properties.Resources.TestResponse1);
        Magic = new Magic();
    }

    private Magic Magic;

    [Test]
    public void Text_Compare_Works()
    {
        Assert.IsTrue(Magic.Validate("yes", new Operation() { value = "yes", perform = OMagic.Equal }));
        Assert.IsFalse(Magic.Validate("yes", new Operation() { value = "no", perform = OMagic.Equal }));
        Assert.IsTrue(Magic.Validate("yes", new Operation() { value = "no", perform = OMagic.NotEqual }));
        Assert.IsFalse(Magic.Validate("yes", new Operation() { value = "yes", perform = OMagic.NotEqual }));
    }

    [Test]
    public void Int_Compare_Works()
    {
        Assert.IsFalse(Magic.Validate(7, new Operation(){value = 7, perform=OMagic.LengthGreaterThan}));
        Assert.IsTrue(Magic.Validate(7, new Operation() { value = 8, perform = OMagic.LengthGreaterThan }));
        Assert.IsFalse(Magic.Validate(7, new Operation() { value = 7, perform = OMagic.LengthLessThan }));
        Assert.IsTrue(Magic.Validate(7, new Operation() { value = 6, perform = OMagic.LengthLessThan }));
        Assert.IsFalse(Magic.Validate(7, new Operation() { value = 8, perform = OMagic.LengthEqual }));
        Assert.IsTrue(Magic.Validate(7, new Operation() { value = 7, perform = OMagic.LengthEqual }));
    }
\$\endgroup\$
  • 1
    \$\begingroup\$ First, I think this sounds more appropriate for Programmers. Second, I cannot understand why I would use Magic.Validate("yes", new Operation() { value = "yes", perform = OMagic.Equal }) rather than "yes".Equals("yes"), etc. \$\endgroup\$ – Magus Aug 1 '14 at 22:42
  • 1
    \$\begingroup\$ I think you should have a look @ weblogs.asp.net/scottgu/… \$\endgroup\$ – Thomas Junk Aug 2 '14 at 16:25
  • \$\begingroup\$ @ThomasJunk thanks for the article, but I am trying to stay away from writing bulky link queries. I was looking for something that could reduce the amount of code I would need to pass in. I also was thinking of using funcs, just couldn't remember how to use them. \$\endgroup\$ – DeadlyChambers Aug 2 '14 at 18:26
  • \$\begingroup\$ @Magus I don't usually use the equals, but I will start to explore that option. It seems like a cleaner way, but are you saying this question sounds more appropriate for programmers? This is working code (also very ugly), I just wanted someone to review it and give some advice/better solution. \$\endgroup\$ – DeadlyChambers Aug 2 '14 at 18:30
  • \$\begingroup\$ Again, its not about .Equals() it's about your goal. You want to know if something meets some condition. But ultimately, Assert.IsFalse(Magic.Validate(7, new Operation(){value = 7, perform=OMagic.LengthGreaterThan})); is no different from Assert.IsFalse(7 > 7); - in other words, your .Validate() method does nothing. There is no point even writing a more flexible one. For simple comparisons, just compare. \$\endgroup\$ – Magus Aug 4 '14 at 15:42
2
\$\begingroup\$

Well there is multiple solution to this problem ,

  • Using delegate:

    public bool Validate<T1,T2>(T1 value, T2 compareValue, Func<T1,T2,bool> operation)
    {
        return operation(value, compareValue);
    }
    magic.Validate(1, 2, (a, b) => a > b);
    magic.Validate("Testing", "Testing", (a, b) => a.Equals(b));
    

but twp problems with this code is : first your input can be limited , right now you cannot compare more than two values , so you might need to see what can be done to extend this code.

second you can make a switch case to return the right method for comparision.

  • Using the Expression which could be more compact and will be cleaner code. I have not tried this yet.

  • Avoid using private variable naming with capital letters.

  • Avoid giving a name where two capital letters are at start (OMagic), you could write this like OperationMagic.

  • Avoid boxing and unboxing (if your operations are small dont worry).

\$\endgroup\$
  • \$\begingroup\$ I just threw some random stuff together for the sake of putting it online. The private vars, and double caps are gone. I also am passing only strings through so there is no more casting. That is the exact solution I was thinking of. I will test it out monday when I get back to work. I am working on a personal project right now. But that is great. If it works I will accept your answer. Thanks. \$\endgroup\$ – DeadlyChambers Aug 2 '14 at 18:21
  • \$\begingroup\$ The main problem with this solution is that .Equals() has an overload that takes an IEqualityComparer as far as I know, which does this in a more detailed way. Regardless, for something like checking if something is greater than something else, I'd suggest just using the < operator by itself. The .Validate() method does not seem to do anything other than hold an actual comparison. \$\endgroup\$ – Magus Aug 4 '14 at 14:33
  • \$\begingroup\$ the whole point of above code is that we can minimize the LOC , without doing anything special , I agree that are other solution too which I have not looked it yet \$\endgroup\$ – paritosh Aug 4 '14 at 14:45
1
\$\begingroup\$

After writing up a whole question about how to do this with your validation method, decided to scrap it and show you this:

public static class Validation
{
  public static bool Equal(object first, object second)
  {
    return first.Equals(second);
  }

  public static bool GreaterThan(int first, int second)
  {
    return first > second;
  }
  ...
}

This is just a class of validation methods. Just the specific, needed methods.

Converting user input could get a bit annoying, but you'd probably end up with something like this (note that the following is pseudocode):

...
operand = textbox.Text;
result = (bool)typeOf(Magic).GetMethod(combobox.SelectedItem).Invoke(source, operand);
...

This uses reflection, which I am normally loath to do - but this is a situation where it makes the code simpler. You should only ever need to do it when you first take user input, though, so it isn't likely to be a huge issue. You can store the particular invocation and arguments as a delegate if needed for execution later.

\$\endgroup\$
  • \$\begingroup\$ Loath reflection, you're not alone. That is an interesting solution. \$\endgroup\$ – DeadlyChambers Aug 4 '14 at 20:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.