使用Visual Studio 2010对C#非常陌生。在我的旧PHP中,要构建此菜单,我要做的是有2个超链接数组。如果“请求者”登录,将显示Level1数组,如果“管理员”登录,则Level1和Level2数组将被合并并排序并显示。 在C#中,在我的默认页面(有一个Site.Master页面)上,我发现自己这样做了:
case NewCourseRequestView.Administrator:
if (access.Administrator)
{
UserTypeLabel.Text = "Administrator Details:";
AdministratorMenuList.Items.Add("View Un-Approved Requests");
adminContent.Visible = true;
}
break;
case NewCourseRequestView.Requestor:
if (access.Requestor)
{
UserTypeLabel.Text = "Requester Details:";
RequestorMenuList.Items.Add("Request A New Course");
RequestorMenuList.Items.Add("View My New Course Requests");
requestContent.Visible = true;
}
break;
我怎么能
我需要一个相当具体的解释,谢谢!
答案 0 :(得分:1)
我建议的第一件事是你需要一个对象作为你的集合的类型,这些对象将有一个URL和一个Text属性。
class UrlText : IEquatable<UrlText>
{
public string Url { get; set; }
public string Text { get; set; }
public UrlText(string url, string text)
{
this.Url = url;
this.Text = text;
}
#region IEquatable<UrlText> Members
public bool Equals(UrlText other)
{
return this.Url.Equals(other.Url);
}
#endregion
}
现在您继续使用您的代码,稍作修改:
string baseUrl = "http://localhost/myapp";
case NewCourseRequestView.Administrator:
if (access.Administrator)
{
UserTypeLabel.Text = "Administrator Details:";
AdministratorMenuList.Items.Add(new UrlText(baseUrl + "/viewunapproved.aspx", "View Un-Approved Requests"));
adminContent.Visible = true;
}
break;
case NewCourseRequestView.Requestor:
if (access.Requestor)
{
UserTypeLabel.Text = "Requester Details:";
RequestorMenuList.Items.Add(new UrlText(baseUrl + "/RequestCourse.aspx","Request A New Course"));
RequestorMenuList.Items.Add(new UrlText(baseUrl + "/viewNewRequest.aspx","View My New Course Requests"));
requestContent.Visible = true;
}
break;
最后,每当你想要合并集合时,做一些简单的事情:
public static List<UrlText> MergeLists(List<UrlText> listAdmin, List<UrlText> listUser)
{
List<UrlText> result = new List<UrlText>();
foreach (UrlText myMenuItem in listAdmin)
{
result.Add(myMenuItem);
}
foreach (UrlText myMenuItem in listUser)
{
if (!result.Contains(myMenuItem))
result.Add(myMenuItem);
}
return result;
}
并使用它(从接口实现的equals方法允许我们正确使用列表的Contains方法):
mergedList = MergeLists(AdministratorMenuList, RequestorMenuList);
答案 1 :(得分:1)
无论您使用何种语言,我建议您先从设计开始。 想象一下,您需要添加一个具有不同的用户类型(例如,“Guest”) 一套菜单项。 那么需要做什么?再添加一个“if”语句,基本上是复制粘贴。 这根本不好。现在想象当你有10种用户类型时会发生什么。 你的switch-case语句将成为巨大的怪物,你团队中的每个人(甚至你)都会害怕在那里添加一个新项目或改变现有项目。
好的,这很难过,现在让我们玩得开心吧。)
理想情况下,我认为您将要放入Page_Load方法的“客户端”代码只有一行:
protected void Page_Load(object sender, EventArgs e){
BuildMenu();
}
在你的方法中只有一行并且让所有东西“神奇地”整理出来是多么酷。
假设我们有某种策略来管理用户类型的可用项目。 基本界面非常简单:
public abstract class MenuItemsPolicy{
public abstract List<MenuItem> GetMenuItems();
protected virtual MenuItem CreateMenuItem(string text, string url){
//add parameter checks, etc.
MenuItem item = new MenuItem();
item.Text = text;
item.NavigateUrl = url;
return item;
}
}
目前,我们有两种用户类型,因此我们将有两种实现方式。 请求者:
public class RequestorMenuItems : MenuItemsPolicy{
public override List<MenuItem> GetMenuItems(){
return new List<MenuItem>(){
CreateMenuItem("Request A New Course", "~/Courses/RequestNewCourse.aspx"),
CreateMenuItem("View My New Course Requests", "~/Courses/ViewMyCourseRquests.aspx")
};
}
}
和管理员(注意“合并”的地方)
public class AdministratorMenuItems : MenuItemsPolicy{
public override List<MenuItem> GetMenuItems(){
List<MenuItem> resultingMenuItems = (new RequestorMenuItems()).GetMenuItems();
resultingMenuItems.Add(CreateMenuItem("View Un-Approved Requests", "~/Administration/ViewUnAprroved.aspx"));
return resultingMenuItems;
}
}
如您所见,我们检索Requestor的项目,然后在那里再添加一项。 如果将来需要更改,您的客户端/调用代码将一无所知 实现细节,因为您依赖于抽象实体。这意味着您的客户端/调用代码不需要更改规则将被更改;或者如果将来需要更改特定用户类型的可用链接。
为了简化示例,我使用了用户类型的枚举:
public enum UserAccessType{
Requestor = 0,
Administrator = 1
}
现在,让我们看一下实现。 我在页面上放置了一个简单的标准asp.net菜单控件:
<form id="form1" runat="server">
<asp:menu runat="server" Id="mainMenu"></asp:menu>
<div>
这是“代码隐藏”:
public partial class _Default : System.Web.UI.Page{
//We will initialize this variable a bit later
//for example from URL parameter ?userType=1 or something like that
private UserAccessType _currentUserAccess;
//Ideally, dictionary should be a member of a class
//I left a simple dictionary just to avoid over-complicaation
private readonly Dictionary<UserAccessType, MenuItemsPolicy> _userMenuItems = new Dictionary<UserAccessType, MenuItemsPolicy>();
protected override void OnInit(EventArgs e){
//Associating our user types with Menu Items
_userMenuItems.Add(UserAccessType.Administrator, new AdministratorMenuItems());
_userMenuItems.Add(UserAccessType.Requestor, new RequestorMenuItems());
//Init the Current User / Access Type. For example, you can read the value from Request["UserType"]
//Here I've just assigned a value
_currentUserAccess = UserAccessType.Administrator;
base.OnInit(e);
}
protected void Page_Load(object sender, EventArgs e){
BuildMenu();
}
private void BuildMenu(){
mainMenu.Items.Clear();
var menuItems = GetMenuItems();
foreach(var item in menuItems){
mainMenu.Items.Add(item);
}
}
private List<MenuItem> GetMenuItems(){
MenuItemsPolicy currentPolicy = _userMenuItems[_currentUserAccess];
return currentPolicy.GetMenuItems();
}
}
我希望,上面的例子可以回答你的问题。 当然,这个例子并不理想。但是,它有助于保持代码相对清洁和可维护。
P.S。我建议你阅读这篇文章: http://objectmentor.com/resources/articles/Principles_and_Patterns.pdf
参考OCP示例 - 您将看到,它与您的情况有多接近。
感谢阅读:)