Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
463 views
in Technique[技术] by (71.8m points)

properties - Pass property itself to function as parameter in C#

I am looking for a method to pass property itself to a function. Not value of property. Function doesn't know in advance which property will be used for sorting. Simplest way in this example is: creating 4 overwrites with different parameter types. Other way is using of typeof() inside function. Both these ways are unacceptable when Class1 has hundreds properties. So far I found following method:

class Class1
{
    string vehName;
    int maxSpeed;
    int fuelCapacity;
    bool isFlying;
}

class Processor
{
    List<Class1> vehicles = null;
    Processor(List<Class1> input)
    {
        vehicles = input;
    }

    List<Class1> sortBy(List<Class1> toSort, string propName)
    {
        if (toSort != null && toSort.Count > 0)
        {
            return toSort.OrderBy(x => typeof(Class1).GetProperty(propName).GetValue(x, null)).ToList();
        }
        else return null;
    }
}

class OuterUser
{
    List<Class1> vehicles = new List<Class1>();
    // ... fill the list
    Processor pr = new Processor(vehicles);
    List<Class1> sorted = pr.sortBy("maxSpeed");
}

I don't like this method because of risk of "human error" when passing string to processing function. When the string is generated by other part of code this is going be even more ugly. Please, suggest more elegant way to implement passing of Class1 property to function for further processing. The best option for usage IMHO will be (or something like this):

vehicles = sortBy(vehicles, Class1.maxSpeed);
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You can pass a property accessor to the method.

List<Class1> SortBy(List<Class1> toSort, Func<Class1, IComparable> getProp)
{
    if (toSort != null && toSort.Count > 0) {
        return toSort
            .OrderBy(x => getProp(x))
            .ToList();
    }
    return null;
}

You would call it like this:

var result = SortBy(toSort, x => x.maxSpeed);

But you could go one step further and write your own extension method.

public static class CollectionExtensions
{
    public static List<TSource> OrderByAsListOrNull<TSource, TKey>(
        this ICollection<TSource> collection, Func<TSource,TKey> keySelector)

        if (collection != null && collection.Count > 0) {
            return collection
                .OrderBy(x => keySelector(x))
                .ToList();
        }
        return null;
    }
}

Now you can sort like this

List<Class1> sorted = toSort.OrderByAsListOrNull(x => x.maxSpeed);

but also

Person[] people = ...;
List<Person> sortedPeople = people.OrderByAsListOrNull(p => p.LastName);

Note that I declared the first parameter as ICollection<T> because it must fulfill two conditions:

  1. It must have a Count property
  2. It must be an IEnumerable<T> in order to be able to apply the LINQ method OrderBy.

List<Class1> is an ICollection<T> but also an array Person[] as many other collections.


So far, I have shown how you can read a property. If the method needs to set a property, you need to pass it a setter delegate as well

void ReadAndWriteProperty(Func<Class1, T> getProp, Action<Class1, T> setProp)

Where T is the type of the property.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...