问题仅用于教育目的。
我有一个 MVC 应用程序,它有 3 个 Web Journeys,它们在许多方面相互镜像 - 这使得引入处理公共(public)部分的基类变得很方便。
我还使用了很多被放入 viewData
中的类属性
这使得在旅程之间重用 View 时变得很方便,我可以在每个旅程中插入不同的电话号码(或其他位),而无需在每个 viewModel 中继承此数据,因为每个旅程都是相同的(如图所示无法放置到母版页中)在许多不同的观点)。在生成电子邮件等时,这些常量也用在代码中。
[LayoutViewData(ContactNumber = ContactNumber, LegalType = LegalType, LegalReference = LegalReference)]
public class JourneyController : BaseJourneyController
{
private const string ContactNumber = "0800 161 5191";
private const string ContactNumberForPricingPage = "0800 051 3322";
private const string ProductReference = "LS0083";
private const string LegalReference = "conveyancing";
}
public class LayoutViewDataAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.Controller.ViewData.Add("ContactNumber", this.ContactNumber);
}
...
}
我正在尝试解决的问题:
有些方法在旅程中几乎相同,可以移至基础,但它们需要来自常量的值。问题是只有静态可以传递给属性,这意味着我不能简单地将它们更改为仅具有 setter/getter 的抽象属性并继续我的生活。
我的选择:
更改方法签名以将这些常量传递给方法 - 我不喜欢这样,因为必须将数据传递给基类表明实现应该在类本身中进行。
引入抽象的 Get 方法,然后返回常量以用于基类,例如。
protected override string GetContactNumber() { return ContactNumber; }
我不喜欢没有办法强制返回那些特定的常量,感觉有点老套,但恕我直言,这是最省力的最佳解决方案。
摆脱常量和属性,引入具有抽象属性的 BaseViewModel 类,以及为每个旅程设置值的一种机制。或者可以是 3 个已经设置了这些属性的基类。 - 不喜欢,很多替代品。
您能想出一些其他的解决方案,以最少的工作量和最少的黑客攻击来解决我的情况。
最佳答案
我认为您这里的主要问题是您将属性用于不适合的目的。属性用于将元数据添加到代码构造中。但是您正在使用它们来附加数据,这些数据通常应该是实际对象定义的一部分(作为属性 getter )。
此外,我认为您不一定非得求助于类继承才能提出适用于这种情况的设计。但如果您需要,此解决方案仍然有效。
独立接口(interface)
如果将每条数据分解成其自己的接口(interface),则可以利用一个类可以实现多个接口(interface)的事实来根据需要覆盖默认值。
public interface IContactNumber
{
string ContactNumber { get; }
}
单独的 Action 筛选器
与其继承具有自身内置限制的 ActionFilterAttribute
,不如实现 IActionFilter
以从等式中删除不必要的属性。
public class ContactNumberActionFilter : IActionFilter
{
private readonly string defaultContactNumber;
public ContactNumberActionFilter(string defaultContactNumber)
{
this.defaultContactNumber = defaultContactNumber;
}
public void OnActionExecuted(ActionExecutedContext filterContext)
{
// No implementation
}
public void OnActionExecuting(ActionExecutingContext filterContext)
{
var controller = filterContext.Controller;
var provider = controller as IContactNumber;
var contactNumber = (provider == null) ? this.defaultContactNumber : provider.ContactNumber;
controller.ViewData.Add("ContactNumber", contactNumber);
}
}
那么只需在全局范围内注册您的过滤器即可。
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
// Register the action filter globally and provide a default number
filters.Add(new ContactNumberActionFilter("0800 161 5191"));
// TODO: Make filters for ContactNumberForPricingPage,
// ProductReference, and LegalReference and set their default
// values here.
}
}
用法
现在,如果您想覆盖默认联系电话,您只需在 Controller 中实现 IContactNumber
。如果您不实现此接口(interface),将使用默认号码。
public class HomeController : Controller, IContactNumber
{
public string ContactNumber
{
get { return "0800 161 5192"; }
}
public ActionResult Index()
{
return View();
}
}
请注意,您可以还添加一种方法来打开或关闭此功能,方法是使用属性并在将 ContactNumber
添加到 之前测试其存在ViewData
如果你真的需要一个开/关开关。
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class ContactNumberAttribute : Attribute
{
}
关于c# - 结合类属性参数和插入到 ViewData 的继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34919921/