如何停止在覆盖的字段上继承[Required]注释?

时间:2013-04-11 19:43:26

标签: c# asp.net-mvc data-annotations

我有一个电话号码通知模型(用户通过与他们的帐户关联的电话号码获得紧急情况的通知,他们可以设置这些电话号码的调用顺序)。大多数情况下,模型的电话号码部分是必需的,但在创建新用户时会有一个特殊情况,我们不想强迫它。

我做了一个非常简单的子对象UserCreationPhoneNotificationModel,它继承自上面描述的UserPhoneNotificationModel。还有其他一些小的变化,但是这里的相关变化覆盖了PhoneNumber字段,因此不再需要它。

在父模型中它是

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

在儿童模特中,它只是

public override string PhoneNumber { get; set; }

我认为这可以解决问题,但显然不是。我认为问题是RequiredAttribute会对它有Inherited = true,但事实并非如此,我不完全确定为什么它会被继承到子类中。

我做了双重检查以确保,并且从父级字段中删除Required也使得子类中的字段不是必需的,所以它绝对是某种继承的东西。

5 个答案:

答案 0 :(得分:2)

当您建模的关系不适合时,使用继承来共享行为可能会有问题。您通常不会从使用继承来共享ViewModel之间的行为中获得任何好处,而您可以(并且,在您的情况下,执行)遇到问题。

最好的办法是为每个用例使用不同的模型类。如果您确实需要在ViewModel之间共享行为,则可以使用合成。

答案 1 :(得分:1)

可以通过隐藏现有同一个新属性来实现。 因此,如果该属性在父类中是这样的:

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

您可以像下面这样在子类中定义新属性:

public new string PhoneNumber { get; set; }

这将在子类中隐藏PhoneNumber属性及其属性。现在,您可以使用其他任何属性。例如,您可以向子类中的属性添加[PhoneNumber]属性。

答案 2 :(得分:0)

以下示例可能会对您有所帮助。

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

这是Signin模型,我已经继承了另一个模型,但电子邮件不需要它的代码如下:

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

我在另一个模型中覆盖了电子邮件属性

答案 3 :(得分:0)

不继承属性是没有意义的。

覆盖时删除[Required]属性基本上违反了 LSP

  

如果NotRequiredDerivedRequiredBase的子类型,则RequiredBase类型的对象可以替换为NotRequiredDerived类型的对象(即RequiredBase类型的对象{1}}可以替换为子类型NotRequiredDerived的任何对象,而不会改变程序的任何所需属性。

用简单的代码表示:

var requiredPhoneNumber = new RequiredBase() { PhoneNumber = "123456789" };

HandleRequiredBaseObject(requiredPhoneNumber); //Works

var optionalPhoneNumber = new NotRequiredDerived() { PhoneNumber = null };

HandleRequiredBaseObject(optionalPhoneNumber); //Fails

HandleRequiredBaseObject(RequiredBase obj)固有地假定PhoneNumber是必需的(根据RequiredBase类的定义);并且它不期望收到缺少此约束的派生对象!这将导致运行时异常。

不违反LSP的唯一方法是确保在派生类上不违反[Required]约束;这意味着首先尝试删除[Required]注释是没有意义的。

我可以想到一个理论的情况,其中不继承该属性是有意义的:如果属性扩展有效选项的范围,而不是限制它。

假设我们创建了一个类PositiveNumber和一个将其设置为也允许负数的属性:

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

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

如果Base允许所有数字,并且Derived仅允许正数,那么它本身并不违反LSP。

然而,这似乎是一种非常强迫的情况。使用有限的类型,然后通过属性扩展,这不是你真实要遇到的。

对于您的情况,您根本不应该从另一个继承一个viewmodel。

需要不同属性的事实是您不应继承这些类的主要原因!他们应该彼此不同地工作,因此不应该假装一个是另一个的推导。

答案 4 :(得分:-3)

如果使用C#4.0,

如何编写'new'构造函数。

public new string PhoneNumber { get; set; }

我不确定它是否运作良好。