views:

60

answers:

1

The error message I receive is:

At least one object must implement IComparable

The code causing this is below:

private static IEnumerable<Result> setOrderBy(IEnumerable<Result> value, string order)
{
    if (order.Equals("ASC"))
    {
        //value = value.OrderBy(c => c, new SearchService.ResultComparer<Attribute>());
        value = value.OrderBy<Result>(o => o.StringAttributes.Where(p => p.AttributeName == "Title"), new SearchService.ResultComparer<Attribute>());
        //value = value.OrderBy(o => o.StringAttributes.Where(p => p.AttributeName == "Title"), new SearchService.ResultComparer<AttributeItem>()));
    }
    if (order.Equals("DESC"))
    {
        value = value.OrderByDescending(c => c, new SearchService.ResultComparer<Attribute>());
        //value = value.OrderByDescending(o => o.StringAttributes.Where(p => p.AttributeName == "MatterName"));
    }
    return value;
}

A little background: In my MVC2 application, I perform a search in my Search controller. When I send my results to the Results view, I am trying to order the results alphabetically, in ascending or descending order. However, when I write out the logic to set the OrderBy property for my result object I get the squiggly red line underneath the code (as seen in VS2008). For some reason the method doesn't like the data model I am trying to do a sort upon. Each Result object has various properties, one of which is a list of attributes of type string (hence the name StringAttributes) I am trying to sort each Result object in my IEnumerable collection by the value of one of the String Attributes which is present in ALL of my result records.

Help please!

+2  A: 

I think you need to use First() or Single instead of Where() in the place where you are picking out the Attribute to order by. At the moment you are asking OrderBy to calculate order using an IEnumerable<Attribute>, rather than a particular attribute.

value = value.OrderBy<Result>(o => o.StringAttributes.Single(p => p.AttributeName == "Title"), new SearchService.ResultComparer<Attribute>());

or

value = value.OrderBy<Result>(o => o.StringAttributes.First(p => p.AttributeName == "Title"), new SearchService.ResultComparer<Attribute>());
Samuel Jack
I have tried your method and get the same squiggly line, which tells me:"The type arguments for the method cannot be inferred from the usage. Tryspecifying the arguments explicitly"I have removed the type suffix from the OrderBy leaving me with:value.OrderBy(o => o.StringAttributes.First(p => p.AttributeName == "Title"), new SearchService.ResultComparer<Attribute>());This doesnt work however :sIf I just pass in the model, I dont get an error, but I will not be doing orderby using the correct criteria. i.e value.OrderBy<Result>(o => o, new SearchService.ResultComparer<Attribute>());
What is the type of the StringAttributes collection? Is it IEnumerable<Attribute> or is it something else? You need to make sure that the type matches with the type of the IComparer that you are passing in. If StringAttributes is IEnumerable<StringAttribute> then you need to pass in an IComparer<StringAttribute>
Samuel Jack
StringAttributes is a List<Attribute>. Each Attribute has 2 properties:AttributeName and a List<AttributeItems>Each AttributeItem is a list of possible values for the Attribute.For each Result the AttributeItems should only be the values associated with that record..
And does SearchService.ResultComparer<Attribute>() implement IComparer<Attribute>?
Samuel Jack
SearchService.ResultComparer<Atribute> does indeed. Signature below:public class ResultComparer<T> : IComparer<Result>{}
That looks like it might be your problem: it's implementing IComparer<Result> when it should be implementing IComparer<Attribute>. From all that you've written, it looks like you intended the signature to be ResultComparer<T> : IComparer<T> {}
Samuel Jack
If I change the signature of the method to: ResultComparer<T> : IComparer<T> {}...does that make the whole thing generic and not tied into the Result object?The ResultComparer object has been used in other cases as it is, but passing in <DateTime> or other subclasses of user defined objects. And even if the method is written wrong, surely it wouldnt cause a syntaxx error when using the OrderBy function?
How is your ResultComparer doing the comparison?
Samuel Jack
public int Compare(Result x, Result y) { switch (typeof(T).ToString()) { case "System.DateTime": return string.Compare(x.DateTimeAttributes.FirstOrDefault() == null ? null : x.DateTimeAttributes.FirstOrDefault().AttributeItems.FirstOrDefault().Value, y.DateTimeAttributes.FirstOrDefault() == null ? null : y.DateTimeAttributes.FirstOrDefault().AttributeItems.FirstOrDefault().Value); default: return string.Compare(string.Empty, string.Empty); } }
OK, it looks like you'll need to create a new comparer specifically to compare Attribute. Your use of generics in this case is ... unusual.
Samuel Jack
The source code for the Comparer wasnt written by me, and I have only recently been granted access to the source. Previously, I had the DLLs only and used reflection to expose the class methods.Other uses of the comparer show that even though it is typed as a <Result> it could still use other subclasses.E.g private static IEnumerable<Result> setOrderBy(IEnumerable<Result> value, IBaseModel model) { switch (model.SelectedOrderBy) { case "DateTimeAttributes_Desc": value = value.OrderByDescending(o => o, new ResultComparer<DateTime>()); break; }}
I have solved it!value = value.OrderBy(o => o.StringAttributes .Where(p => p.AttributeName == "Title") .Select(p => p.AttributeItems) .FirstOrDefault() .Select(p=> p.Value) .FirstOrDefault());What I do is drill inwards through the nested lists within the Results object. That is, I access the inner list of Attributes, then access the inner list of Attributeitems, get the value of the AttributeItem and sort the whole object by this string value, negating the need for a comparer object. Woohoo!