开发者

Use generics to make a method work for any data type

I'm not quite sure I'm understanding how I can utilize generics in C# properly. Say I have the following method. I would like to allow it to work on Lists of any type. Currently I have List where Row is a custom struct, I want to reuse this sort method for half a dozen structs that I make. I thought I could just do List<T> in the return type and parameter t开发者_如何学编程ype but it doesn't like that.

public static List<Row> SortResults( List<Row> listRow, string sortColumn, bool ascending)
        {
            switch (ascending)
            {
                case true:
                    return (from r in listRow
                            orderby r.GetType().GetField(sortColumn).GetValue(r)
                            select r).ToList<Row>();
                case false:
                    return (from r in listRow
                            orderby r.GetType().GetField(sortColumn).GetValue(r) descending
                            select r).ToList<Row>();
                default:
                    return listRow;
            }
        }


Well, here's your original code made generic:

public static List<T> SortResults<T>(List<T> listRow, 
                                     string sortColumn, bool ascending)
{
    switch (ascending)
    {
        case true:
            return (from r in listRow
                    orderby r.GetType().GetField(sortColumn).GetValue(r)
                    select r).ToList();
        case false:
            return (from r in listRow
                    orderby r.GetType().GetField(sortColumn).GetValue(r) descending
                    select r).ToList();
        default:
            return listRow;
    }
}

Note how I've removed the type argument from the ToList calls - let the compiler work it out :)

(As an aside, I don't know why the compiler requires a default case here. Maybe it just always assumes there will be unlisted potential values.)

However, this can be made nicer:

public static List<T> SortResults<T>(List<T> listRow, 
                                     string sortColumn,
                                     bool ascending)
{
    FieldInfo field = typeof(T).GetField(sortColumn);
    Func<T, object> projection = t => field.GetValue(t);
    IEnumerable<T> sequence = ascending ? listRow.OrderBy(projection)
        : listRow.OrderByDescending(projection);
    return sequence.ToList();
}

This is still fairly inefficient (as it's using reflection) but at least it's not getting the FieldInfo separately for each item. If you want better performance, you can have a generic helper type which caches a delegate mapping a value to the field's value for each field, and then fetch that delegate once at the start of the method. It would definitely be more work, but I'd expect it to be an order of magnitude faster.


public static List<T> SortResults( List<T> listObject, string sortColumn, bool ascending) where T: class

Then your ToList would be ToList<T>();

T represents your entity/object type.


You need to make the method itself generic:

public static List<Row> SortResults<Row>( List<Row> listRow, ...
                                   ^^^^^
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜