2012-04-16 122 views
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?

我需要一個相當具體的解釋,謝謝!

回答

1

我建議你從設計開始首先,不管你使用什麼語言。 想象一下,您將需要添加一個具有不同 菜單項集的更多用戶類型(例如「Guest」)。 然後需要做什麼?添加一個「if」語句,基本上覆制粘貼。 這並不好。現在想象一下當你有10個用戶類型時會發生什麼。 您的開關盒聲明將成爲巨型怪物,團隊中的每個人(即使您)都會害怕在其中添加新項目或更改現有項目。

好吧,那是可悲的,我們現在有一些樂趣:)

理想情況下,你的「客戶」的代碼,我想你要放到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(); 
    } 
} 

我希望,上面的例子回答您的問題。 這個例子當然並不理想。但是,它有助於保持代碼的相對清潔和可維護性。

P.S.我建議您閱讀文章: http://objectmentor.com/resources/articles/Principles_and_Patterns.pdf

參考OCP示例 - 您會看到,它與您的情況有多接近。

感謝閱讀:)

+0

謝謝米哈伊爾,我列舉了我提到的用戶,我認爲這是一個很好的計劃,所以非常感謝您將它列入您的回覆。我會閱讀這篇文章,並通過我的項目工作。乾杯- – Jazzy 2012-04-17 14:48:11

1

我建議的第一件事是,你需要一個對象作爲您的集合類型,這些對象將有一個網址和一個文本屬性。

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); 
+0

這絕對是美麗的。 – Jazzy 2012-04-16 23:35:17