How to stop annotation [Required] from being inherited with redefined fields?

I have a model for notification of a phone number (users receive emergency notifications by phone numbers that they associate with their account, and they can indicate in what order they are called). In most cases, a phone number is required in the model, but there is a special case when creating a new user, where we do not want to force him.

I created a very simple child object UserCreationPhoneNotificationModel, which inherits from the UserPhoneNotificationModel described above. There are a couple of other small changes, but the corresponding one overrides the PhoneNumber field so that it is no longer required.

In the parent model, this

[Required] public virtual string PhoneNumber { get; set; } 

And in a child’s model, it's just

 public override string PhoneNumber { get; set; } 

I decided that it would be a trick, but apparently not. I thought the problem is that RequiredAttribute has Inherited = true, but it is not, I'm not quite sure why it is inherited in a subclass.

I did a double check to make sure the removal of the Required from the parent field also did not require the field in the subclass, so this is definitely some kind of inheritance thing.

+4
source share
5 answers

Using inheritance to share behavior when the relationship you are modeling is not appropriate can be problematic. Usually you do not get any benefit from using inheritance to share behavior between ViewModels, while you can (and, as in your case, do) run into problems.

It is best to use a different model class for each use case. If you really need to share behavior between ViewModels, you can do this with composition.

+2
source

Below example can help you.

 public class SigninModel { [Required] [EmailAddress] public virtual string email { get; set; } [Required] [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)] [DataType(DataType.Password)] public string password { get; set; } } 

This is a Signin model, and I inherit another model, but its code is not required by email, as shown below:

 public class ExternalLoginModel : SigninModel { public override string email { get; set; } public string LoginProvider { get; set; } public string ProviderKey { get; set; } } 

I override the email property in another model

0
source

It makes no sense not to inherit the attribute .

Removing the [Required] attribute when overriding substantially violates the LSP .

If NotRequiredDerived is a subtype of RequiredBase , then objects of type RequiredBase can be replaced with objects of type NotRequiredDerived (i.e. an object of type RequiredBase can be replaced by any object of a subtype NotRequiredDerived ) without changing any desired properties of the program.

To express this with simple code:

 var requiredPhoneNumber = new RequiredBase() { PhoneNumber = "123456789" }; HandleRequiredBaseObject(requiredPhoneNumber); //Works var optionalPhoneNumber = new NotRequiredDerived() { PhoneNumber = null }; HandleRequiredBaseObject(optionalPhoneNumber); //Fails 

HandleRequiredBaseObject(RequiredBase obj) essentially assumes that PhoneNumber is required (as defined by the RequiredBase class); and he does not expect to receive a derivative that lacks this restriction! This will result in runtime exceptions.

The only way to not violate the LSP is to ensure that the [Required] constraint is not violated on derived classes; this means that it makes no sense to try to remove the [Required] annotation first.


I can come up with one theoretical case where the meaning of attribute inheritance does not make sense: if the attribute extends the range of valid parameters, but does not limit it.

Suppose we create a PositiveNumber class and an attribute that sets it as well to resolve negative numbers:

 public class Base { [NegativesAllowed] public PositiveNumber Number { get; set; } } public class Derived : Base { public PositiveNumber Number { get; set; } } 

If Base allows all numbers, and Derived allows only positive numbers, then this does not in fact violate the LSP.

However, this seems like a very strong situation. Using a limited type, which is then expanded with an attribute, is not something you are about to encounter.


In your case, you simply should not inherit one model from another.

The fact that different attributes are required is the main reason why you should not inherit these classes! They must work differently from each other, and therefore should not pretend that one is a derivation of the other.

0
source

This can be done by hiding an existing property with a new name with the same name. So, if the property in the parent class is as follows:

 [Required] public virtual string PhoneNumber { get; set; } 

You can define a new property in a child class as follows:

 public new string PhoneNumber { get; set; } 

This will hide the PhoneNumber property along with its attributes in the child class. Now you can use any other attributes with it. For example, you can add the [PhoneNumber] attribute to a property in a child class.

0
source

If using C # 4.0,

How about writing a "new" constructor.

 public new string PhoneNumber { get; set; } 

I am not sure if it works well.

-2
source

All Articles