Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Foolproof RequiredIf with an Enum

We are trying to use the Foolproof validation annotation [RequiredIf] to check if an email address is needed. We also created an enum to avoid using a lookup table id in the ViewModel. The code looks like this:

public enum NotificationMethods {
        Email = 1,
        Fax = 2
}

Then in the ViewModel:

[RequiredIf("NotificationMethodID", NotificationMethods.Email)]
public string email {get; set;}

In this senario we do not get an error when email is unfilled but selected as the notification type. Conversely this works as expected:

[RequiredIf("NotificationMethodID", 1)]
public string email {get; set;}

The only other reference to this I have found is here: https://foolproof.codeplex.com/workitem/17245

like image 979
Matthew Avatar asked Dec 03 '14 23:12

Matthew


People also ask

What if we used enums instead of booleans?

The bunch of software developers from the story could have avoided these hassles if they’d used enums instead of booleans. An enumerator is a data type consisting of a set of named values that can be used in a type-safe way.

What is the use of enum valueOf () method?

valueOf () method returns the enum constant of the specified string value, if exists. enum can contain a constructor and it is executed separately for each enum constant at the time of enum class loading. We can’t create enum objects explicitly and hence we can’t invoke enum constructor directly.

Can an enum have a constructor?

enum can contain a constructor and it is executed separately for each enum constant at the time of enum class loading. We can’t create enum objects explicitly and hence we can’t invoke enum constructor directly. enum can contain both concrete methods and abstract methods.

What should be the first line inside an enum?

First line inside enum should be list of constants and then other things like methods, variables and constructor. According to Java naming conventions, it is recommended that we name constant with all capital letters Important points of enum : Every enum internally implemented by using Class.


1 Answers

Given that your method NotificationMethodID is returning an int, the reason your check is failing is that, in c#, each enum is its own type, inheriting from System.Enum. I.e. if you do

var value = NotificationMethods.Email;
string s = value.GetType().Name;

You will see s has the value "NotificationMethods" not "Int32".

If you try to check the equality of an int with an enum directly, you get a compiler error:

var same = (1 == NotificationMethods.Email); // Gives the compiler error "Operator '==' cannot be applied to operands of type 'int' and 'NotificationMethods'"

If you box the enum and int values first (which is what happens when they are passed to the constructor of RequiredIfAttribute) then there is no compiler error but Equals() returns false, since the types differ:

var same = ((object)1).Equals((object)NotificationMethods.Email);
Debug.WriteLine(same) // Prints "False".

To check equality of underlying integer values, you can explicitly cast NotificationMethods.Email to an integer before boxing:

var same = ((object)1).Equals((object)((int)NotificationMethods.Email));
Debug.WriteLine(same); // Prints "True"

And in the attribute application:

[RequiredIf("NotificationMethodID", (int)NotificationMethods.Email)]
public string email {get; set;}

You might also consider using const int values instead of enums:

public static class NotificationMethods
{
    public const int Email = 1;
    public const int Fax = 2;
}
like image 145
dbc Avatar answered Oct 11 '22 06:10

dbc