Wesley
Wesley

Reputation: 5621

Returning a Sorted List of Objects based on an Abstract Class

I have an abstract class that defines basic behavior for socially used objects throughout the site (Social Collaboration Objects).

internal abstract class SCO
{
    public double HotScore { get; set; }
    public double UpVotes { get; set; }
    public double DownVotes { get; set; }
    public double VoteTotal { get; set; }
    public DateTime Created { get; set; }

    public SCO(DBItem item, List<Vote> votes )
    {
        var voteMeta = InformationForThisVote(votes, item.ID);
        UpVotes = voteMeta.UpVotes;
        DownVotes = voteMeta.DownVotes;
        VoteTotal = UpVotes - DownVotes;
        HotScore = Calculation.HotScore(Convert.ToInt32(UpVotes), Convert.ToInt32(DownVotes), Convert.ToDateTime(item["Created"]));
        Created = Convert.ToDateTime(item["Created"]);
    }

    private static VoteMeta InformationForThisVote(List<Vote> votes, int itemId)
    {
        // Loop through votes, find matches by id, 
        // and record number of upvotes and downvotes
    }
    private User GetCreatorFromItemValue(DBItem item)
    {
        // Cast User Object from property of DataBase information
    }
}

Here is a sample of inherited object:

class Post : SCO
{
    public string Summary { get; set; }
    public Uri Link { get; set; }
    public Uri ImageUrl { get; set; }

    public Post(DBItem item, List<Vote> votes)
        : base(item, votes)
    {
        Summary = (string) item["Summary"];
        Link = new UriBuilder((string) item["Link"]).Uri;
        ImageUrl = new UriBuilder((string) item["ImageUrl"]).Uri;
    }
}

Something else these classes all have in common is that the majority of the time they will be returned as a Sorted Collection. The difficulty here is you cannot embed a collection into an abstract class, because there is no way to instantiate the abstract class itself.

What I have working so far is having a Sort method as part of the abstract shown here:

    protected static List<ESCO> SortedItems(List<ESCO> escoList, ListSortType sortType)
    {
        switch (sortType)
        {
            case ListSortType.Hot:
                escoList.Sort(delegate(ESCO p1, ESCO p2) { return p2.HotScore.CompareTo(p1.HotScore); });
                return escoList;
            case ListSortType.Top:
                escoList.Sort(delegate(ESCO p1, ESCO p2) { return p2.VoteTotal.CompareTo(p1.VoteTotal); });
                return escoList;
            case ListSortType.Recent:
                escoList.Sort(delegate(ESCO p1, ESCO p2) { return p2.Created.CompareTo(p1.Created); });
                return escoList;
            default:
                throw new ArgumentOutOfRangeException("sortType");
        }
    }

Which allows me to have this in my Inherited Children classes:

    public static List<Post> Posts(SPListItemCollection items, ListSortType sortType, List<Vote> votes)
    {
        var returnlist = new List<ESCO>();
        for (int i = 0; i < items.Count; i++) { returnlist.Add(new Post(items[i], votes)); }
        return SortedItems(returnlist, sortType).Cast<Post>().ToList();
    }

This works, but it feels a little clunky. I'm still repeating a lot of code in my Sub-Classes, and I feel like that cast is an unnecessary performance deduction.

How do I best provide a way to return a sorted list of Objects based on an abstract class which are sorted in the same way, with the same properties?

Upvotes: 1

Views: 1455

Answers (1)

McGarnagle
McGarnagle

Reputation: 102753

It looks like there's no need for the abstract class, since there are no abstract members. Wouldn't it be best just to use a concrete base class (adding virtual members if necessary)?

Better yet, use an interface that contains all the members needed for sorting (score, votes, etc); pass collections of the interface to your sort method.

Edit Here's a simplified example:

internal interface ISCO
{
    double HotScore { get; set; }
}

class SCO : ISCO
{
    public double HotScore { get; set; }

    public static IEnumerable<T> Sort<T>(IEnumerable<T> items) where T : ISCO
    {
        var sorted = items.ToList();
        sorted.Sort();
        return sorted;
    }
}

Then you can use that single sort method for every derived class:

List<Post> PostItems = // ...
IEnumerable<Post> sorted = SCO.Sort<Post>(PostItems);

Upvotes: 3

Related Questions