如何重构此C#代码以使其更易于阅读?

时间:2012-05-31 13:58:11

标签: c# asp.net-mvc-3 refactoring

这是我的控制器中的一个动作 - 在我的整个项目中,我的控制器中有类似的大方法。

我正在努力学习将这些东西放在哪里以及如何清理。我是新手,如果我看到如何更改我自己的代码的一个很好的例子,它可能会教我如何对我的大量代码进行操作。

这是我的行动:

public ActionResult Index(string sortOrder, string currentFilter, string searchString, int? page)
{
    ViewBag.CurrentSort = sortOrder;
    ViewBag.TitleSortParm = String.IsNullOrEmpty(sortOrder) ? "Title desc" : "";
    ViewBag.CreditsSortParm = sortOrder == "Credits" ? "Credits desc" : "Credits";
    ViewBag.ElectiveSortParm = sortOrder == "Elective" ? "Elective desc" : "Elective";
    ViewBag.InstructorSortParm = sortOrder == "Instructor" ? "Instructor desc" : "Instructor";
    ViewBag.YearSortParm = sortOrder == "Year" ? "Year desc" : "Year";
    ViewBag.AttendingDaysSortParm = sortOrder == "AttendingDays" ? "AttendingDays desc" : "AttendingDays";
    ViewBag.AttendanceCapSortParm = sortOrder == "AttendanceCap" ? "AttendanceCap desc" : "AttendanceCap";
    ViewBag.StartDateSortParm = sortOrder == "StartDate" ? "StartDate desc" : "StartDate";
    ViewBag.LocationSortParm = sortOrder == "Location" ? "Location desc" : "Location";
    ViewBag.ParishSortParm = sortOrder == "Parish" ? "Parish desc" : "Parish";
    ViewBag.DescriptionSortParm = sortOrder == "Description" ? "Description desc" : "Description";
    ViewBag.ApprovedSortPArm = sortOrder == "Approved" ? "Approved desc" : "Approved";
    ViewBag.CompletedSortPArm = sortOrder == "Completed" ? "Completed desc" : "Completed";
    ViewBag.ArchivedSortPArm = sortOrder == "Archived" ? "Archived desc" : "Archived";

    if (Request.HttpMethod == "GET")
    {
        searchString = currentFilter;
    }
    else
    {
        page = 1;
    }
    ViewBag.CurrentFilter = searchString;

    var courses = from s in db.Courses
                    select s;
    if (!String.IsNullOrEmpty(searchString))
    {
        courses = courses.Where(s => s.Title.ToUpper().Contains(searchString.ToUpper()));
    }
    switch (sortOrder)
    {
        case "Title desc":
            courses = courses.OrderByDescending(s => s.Title);
            break;
        case "Credits":
            courses = courses.OrderBy(s => s.Credits);
            break;
        case "Credits desc":
            courses = courses.OrderByDescending(s => s.Credits);
            break;
        case "Elective":
            courses = courses.OrderBy(s => s.Credits);
            break;
        case "Elective desc":
            courses = courses.OrderByDescending(s => s.Credits);
            break;
        case "Instructor":
            courses = courses.OrderBy(s => s.Instructor.LastName);
            break;
        case "Instructor desc":
            courses = courses.OrderByDescending(s => s.Instructor.LastName);
            break;
        case "Year":
            courses = courses.OrderBy(s => s.Year);
            break;
        case "Year desc":
            courses = courses.OrderByDescending(s => s.Year);
            break;
        case "AttendingDays":
            courses = courses.OrderBy(s => s.AttendingDays);
            break;
        case "AttendingDays desc":
            courses = courses.OrderByDescending(s => s.AttendingDays);
            break;
        case "AttendanceCap":
            courses = courses.OrderBy(s => s.AttendanceCap);
            break;
        case "AttendanceCap desc":
            courses = courses.OrderByDescending(s => s.AttendanceCap);
            break;
        case "StartDate":
            courses = courses.OrderBy(s => s.StartDate);
            break;
        case "StartDate desc":
            courses = courses.OrderByDescending(s => s.StartDate);
            break;
        case "Location":
            courses = courses.OrderBy(s => s.Location);
            break;
        case "Location desc":
            courses = courses.OrderByDescending(s => s.Location);
            break;
        case "Parish":
            courses = courses.OrderBy(s => s.Parish);
            break;
        case "Parish desc":
            courses = courses.OrderByDescending(s => s.Parish);
            break;
        case "Description":
            courses = courses.OrderBy(s => s.Description);
            break;
        case "Description desc":
            courses = courses.OrderByDescending(s => s.Description);
            break;
        case "Approved":
            courses = courses.OrderBy(s => s.Approved);
            break;
        case "Approved desc":
            courses = courses.OrderByDescending(s => s.Approved);
            break;
        case "Completed":
            courses = courses.OrderBy(s => s.Completed);
            break;
        case "Completed desc":
            courses = courses.OrderByDescending(s => s.Completed);
            break;
        case "Archived":
            courses = courses.OrderBy(s => s.Archived);
            break;
        case "Archived desc":
            courses = courses.OrderByDescending(s => s.Archived);
            break;
        default:
            courses = courses.OrderBy(s => s.Title);
            break;
    }
    int pageSize = 4;
    int pageNumber = (page ?? 1);
    return View(courses.ToPagedList(pageNumber, pageSize));
}

我应该如何处理上述代码以使其更具可读性?我是否只是将其中的一部分作为单独的方法移动并将它们移动到控制器的底部?我是否将这些方法放在另一个文件中并在此引用它?

请记住我正在学习并且很清楚。

2 个答案:

答案 0 :(得分:2)

您如何更改代码将完全是主观的,并且您需要通过创造性过程来感受并努力成为更好的开发人员。

但作为伪代码示例,对象是使您的方法变小。不,真的,甚至更小!

使函数名称非常有意义,并确保它们告诉程序员方法的目的是什么。这只是一个结构样本:

public class Something {

   public ActionResult Index() {
       MakeCallToFunction();
       var something = GetSomething();
       var somethingElse = GetSomethingElse(something);
       var model = new SomeViewModel(somethingElse);
       return View(model);
   }

   private void MakeCallToFunction () {
       ...
   }

   private string GetSomething() {
       ...
       return someVal;
   }

   private SomeObject GetSomethingElse(string something) {
       ...
       return someBigObject;
   }
}

或者它可能意味着你接受所有这些小功能并上课

public class Something {

   public ActionResult Index(int id) {
       var model = new SomeRelatedStuff.Load(id);
       return View(model);
   }
}

private class SomeRelatedStuff {

   public SomeRelatedStuff()

   public static SomeRelatedStuff Load(int id) {
       var something = GetSomething();
       var somethingElse = GetSomethingElse(something);
       var model = new SomeViewModel(somethingElse);
       MakeObject();
       return this;
   }

   private string GetSomething() {
       ...
       return someVal;
   }

   private SomeObject GetSomethingElse(string something) {
       ...
       return someBigObject;
   }

   private void MakeObject () {
       ...
   }

}

作为附注,请请罗伯特·马丁(鲍勃叔叔)获取清洁代码,至少阅读本周末的前4章。然后再读一遍。

答案 1 :(得分:2)

首先,摆脱你的魔法弦。将排序顺序设为枚举,如下所示:

public enum ActionSortOrder {
    Credits,
    Elective,
    ...
}

ActionSortOrder order = ActionSortOrder.Credits;

这比使用未定义的字符串更易于管理,如果其功能需要一些解释,您可以记录枚举成员。

其次,方法顶部的行有些令人困惑:

 ViewBag.CreditsSortParm = sortOrder == "Credits" ? "Credits desc" : "Credits";

因此,如果您将“Credits”作为排序顺序传递,则默认为降序排列?如果你不这样做,它默认为升序?为什么?为什么不给出升序/降序的选项(再次使用枚举而不是魔术字符串)?为什么每次调用此方法时都会保存所有这些排序顺序?这些设定变量在哪里使用?您只能使用此方法中传递的顺序。

另外,不要担心开关看起来很大。 Switch语句通常仅用于避免一堆if-else语句。因此,大多数交换机在实践中都有相当多的情况。

了解有关代码的更多信息有助于评估代码。