合并和排序列表

时间:2012-04-16 21:26:52

标签: c# visual-studio-2010

使用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;

我怎么能

  1. 让这些列表项充当超链接和
  2. 将这两个列表放在2个独立的数组(集合?)中,如果我有访问权限,则将它们合并。管理员?
  3. 我需要一个相当具体的解释,谢谢!

2 个答案:

答案 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示例 - 您将看到,它与您的情况有多接近。

感谢阅读:)