1

对 C# 来说非常新,使用 Visual Studio 2010。在我的旧 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;

我怎样才能

  1. 让这些列表项充当超链接和
  2. 将这 2 个列表放在 2 个单独的数组(集合?)中,如果我有 access.Administrator 则合并它们?

我需要一个相当具体的解释,谢谢!

4

2 回答 2

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);
于 2012-04-16T23:15:28.087 回答
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;
    }
}

如您所见,我们检索请求者的项目,然后在那里再添加一项。如果将来需要更改,您的客户端/调用代码将不了解实现细节,因为您依赖于抽象实体。这意味着您不需要更改客户端/调用代码,规则将被更改;或者如果将来需要更改特定用户类型的可用链接。

为了简化示例,我将枚举用于用户类型:

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

我希望,上面的例子回答了你的问题。当然,这个例子并不理想。但是,它有助于保持您的代码相对干净和可维护。

PS我确实建议你阅读这篇文章: http: //objectmentor.com/resources/articles/Principles_and_Patterns.pdf

请参阅 OCP 示例 - 您会看到它与您的情况有多接近。

谢谢阅读 :)

于 2012-04-16T23:34:00.737 回答