视图模型绑定:当绑定到的 class 是抽象的时,有没有办法访问具体实现的属性?
View model binding: Is there a way to access properties of a concrete implementation, when the class being bound to is abstract?
我试图在 ASP.NET MVC 视图的绑定模型中访问抽象对象的具体实现,但我不知道如何绑定到 属性 的属性这是其具体实施的一部分。
public abstract class BasePageVO
{
public string DisplayText { get; set; }
public BaseFoo FooItem { get; set; }
}
public class ConcretePageVO : BasePageVO
{
// some properties
// in a concrete page, the concrete implementation of BaseFoo is known at compile time.
}
public abstract class BaseFoo
{
public string FooText { get; set; }
}
public class ConcreteFoo : BaseFoo
{
public string ConcreteProperty { get; set; }
}
更重要的是,我采用这种不寻常的 class 结构的原因在于,共享部分还需要了解 FooItem,但只需要了解其抽象属性。结构的简化大纲如下:
DisplayFoo.cshtml:
@model ConcretePageVO
@using (Html.BeginForm("Submit", "Foo", FormMethod.Post)
{
@Html.Partial("DisplayFooShared", @Model)
@Html.EditorFor(x => x.FooItem.ConcreteProperty) @* This fails *@
}
DisplayFooShared.cshtml:
@model BasePageVO
<div>
@Html.DisplayFor(x => x.DisplayText)
@Html.EditorFor(x => x.FooItem.FooText)
@* More properties... *@
</div>
有没有办法向 Razor 指示 BaseFoo 对象是预期的具体类型,并且仍然受益于我在共享局部视图中执行模型绑定的方式?我认为我为 BaseFoo 创建自己的自定义模型绑定是正确的,就像在 Darin's answer here 中一样,但是 ASP.NET 抛出一个编译错误,Razor 不知道如何处理 [=39] =] 名称,因为它未定义。
有没有一种方法可以完成对这些特定于实现的属性的绑定,并且仍然受益于 ASP.NET MVC 提供的强类型化?我在自定义绑定方面是否走在了正确的轨道上,但只是搞砸了实施?在此先感谢您的任何建议。
编辑: 我用 @Html.EditorFor(x => (x.FooItem as ConcreteFoo).ConcreteProperty)
替换了 @Html.EditorFor(x => x.FooItem.ConcreteProperty)
,这导致绑定成功。不过,还有更好的方法吗?
public abstract class BaseFoo
{
public virtual string FooText { get; set; }
}
public class ConcreteFoo : BaseFoo
{
public override string FooText { get; set; }
}
你的所作所为违反了面向对象编程的原则。您有一个基础 class 并且您正试图将其视为派生的 class,这只是一个巨大的危险信号。如果您需要派生 class,那么您的模型中应该有一个派生 class。
否则你唯一的选择就是强制转换,这是一个巨大的代码味道,如果对象实际上不是你认为的派生对象,则可能存在缺陷。
您真正的问题很可能是您正在尝试使用某种域模型作为您的视图模型。您应该自定义您的视图模型,使其完全成为该视图所需的模型。然后你应该将你的域模型映射到你的视图模型,并在此时进行任何必要的转换。
我试图在 ASP.NET MVC 视图的绑定模型中访问抽象对象的具体实现,但我不知道如何绑定到 属性 的属性这是其具体实施的一部分。
public abstract class BasePageVO
{
public string DisplayText { get; set; }
public BaseFoo FooItem { get; set; }
}
public class ConcretePageVO : BasePageVO
{
// some properties
// in a concrete page, the concrete implementation of BaseFoo is known at compile time.
}
public abstract class BaseFoo
{
public string FooText { get; set; }
}
public class ConcreteFoo : BaseFoo
{
public string ConcreteProperty { get; set; }
}
更重要的是,我采用这种不寻常的 class 结构的原因在于,共享部分还需要了解 FooItem,但只需要了解其抽象属性。结构的简化大纲如下:
DisplayFoo.cshtml:
@model ConcretePageVO
@using (Html.BeginForm("Submit", "Foo", FormMethod.Post)
{
@Html.Partial("DisplayFooShared", @Model)
@Html.EditorFor(x => x.FooItem.ConcreteProperty) @* This fails *@
}
DisplayFooShared.cshtml:
@model BasePageVO
<div>
@Html.DisplayFor(x => x.DisplayText)
@Html.EditorFor(x => x.FooItem.FooText)
@* More properties... *@
</div>
有没有办法向 Razor 指示 BaseFoo 对象是预期的具体类型,并且仍然受益于我在共享局部视图中执行模型绑定的方式?我认为我为 BaseFoo 创建自己的自定义模型绑定是正确的,就像在 Darin's answer here 中一样,但是 ASP.NET 抛出一个编译错误,Razor 不知道如何处理 [=39] =] 名称,因为它未定义。
有没有一种方法可以完成对这些特定于实现的属性的绑定,并且仍然受益于 ASP.NET MVC 提供的强类型化?我在自定义绑定方面是否走在了正确的轨道上,但只是搞砸了实施?在此先感谢您的任何建议。
编辑: 我用 @Html.EditorFor(x => (x.FooItem as ConcreteFoo).ConcreteProperty)
替换了 @Html.EditorFor(x => x.FooItem.ConcreteProperty)
,这导致绑定成功。不过,还有更好的方法吗?
public abstract class BaseFoo
{
public virtual string FooText { get; set; }
}
public class ConcreteFoo : BaseFoo
{
public override string FooText { get; set; }
}
你的所作所为违反了面向对象编程的原则。您有一个基础 class 并且您正试图将其视为派生的 class,这只是一个巨大的危险信号。如果您需要派生 class,那么您的模型中应该有一个派生 class。
否则你唯一的选择就是强制转换,这是一个巨大的代码味道,如果对象实际上不是你认为的派生对象,则可能存在缺陷。
您真正的问题很可能是您正在尝试使用某种域模型作为您的视图模型。您应该自定义您的视图模型,使其完全成为该视图所需的模型。然后你应该将你的域模型映射到你的视图模型,并在此时进行任何必要的转换。