简体   繁体   中英

How can I refactor this C# code to make it easier to read?

This is an action within a Controller of mine - I have similar large methods in my Controllers throughout my project.

I am trying to learn where to put these things and how to clean things up. I am new at doing this, if I saw a good example at how to change some of my own code, it would likely teach me how to do it to large amounts of my code.

Here is my action:

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

What should I do to the above code to make it more readable? Do I simply move parts of it out as separate methods and move them to the bottom of the Controller? Do I put the methods in another file somewhere and reference it here?

Please remember I am learning and clarity is enjoyed.

How you change the code will be purely subjective and it's a creative process that you need to feel and fight thru to become a better developer.

But as a pseudocode example, the object is to make your methods small. No, really, even smaller!

Make the function names very meaningful and make sure they tell the programmer what the method's intent truly is. This is just a sample of structure:

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

Or it might mean you take all those little functions and make a class

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 () {
       ...
   }

}

As a side note, PLEASE please please go get Clean Code by Robert Martin (Uncle Bob), read at least the first 4 chapters this weekend. Then read them again.

First of all, get rid of your magic strings. Make a sort order an enum, like this:

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

ActionSortOrder order = ActionSortOrder.Credits;

This is much more manageable than using undefined strings, and you can document the enum members if its functionality needs some explanation.

Second of all, the lines at the top of the method are somewhat confusing:

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

So if you pass "Credits" as the sort order, it defaults to a descending order? And if you don't, it defaults to ascending order? Why? Why not give an option for ascending/descending ordering (again with an enum and not magic strings)? And why are all of these sort orders saved every time this method is called? Where are these set variables used? You only use the order passed in inside this method.

Also, don't worry about switches looking large. Switch statements are usually only used to avoid a bunch of if-else statements. So most switches have quite a few cases in practice.

Knowing more about your code would help in evaluating it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM