Подтвердить что ты не робот

Свойство Pass само может функционировать как параметр в С#

Я ищу способ передать свойство самому функции. Не стоимость имущества. Функция не знает заранее, какое свойство будет использоваться для сортировки. Самый простой способ в этом примере: создать 4 перезаписывания с разными типами параметров. Другим способом является использование внутренней функции typeof(). Оба эти метода неприемлемы, если Class1 обладает сотнями свойств. До сих пор я нашел следующий метод:

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

Мне не нравится этот метод из-за риска "человеческой ошибки" при передаче строки в функцию обработки. Когда строка генерируется другой частью кода, это будет еще более уродливым. Пожалуйста, предложите более элегантный способ реализации передачи свойства Class1 для дальнейшей обработки. Лучшим вариантом использования IMHO будет (или что-то вроде этого):

vehicles = sortBy(vehicles, Class1.maxSpeed);
4b9b3361

Ответ 1

Вы можете передать свойство доступа к методу.

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

Вы бы назвали это следующим образом:

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

Но вы можете сделать еще один шаг и написать свой собственный метод расширения.

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

Теперь вы можете сортировать как это

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

но также

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

Обратите внимание, что я объявил первый параметр как ICollection<T>, потому что он должен выполнять два условия:

  • Он должен иметь свойство Count
  • Он должен быть IEnumerable<T>, чтобы иметь возможность применить метод LINQ OrderBy.

List<Class1> - это ICollection<T>, но также массив Person[] как и многие другие коллекции.

Ответ 2

Вы можете использовать выражение лямбда для передачи информации о свойствах:

void DoSomething<T>(Expression<Func<T>> property)
{
    var propertyInfo = ((MemberExpression)property.Body).Member as PropertyInfo;
    if (propertyInfo == null)
    {
        throw new ArgumentException("The lambda expression 'property' should point to a valid Property");
    }
}

Использование:

DoSomething(() => this.MyProperty);

Ответ 3

Почему вы не используете Linq для этого? Как:

vehicles.OrderBy(v => v.maxSpeed).ToList();

Ответ 4

То, что я нашел отсутствующим в ответе @MatthiasG, - это как получить значение свойства, а не только его имя.

public static string Meth<T>(Expression<Func<T>> expression)
{
    var name = ((MemberExpression)expression.Body).Member.Name;
    var value = expression.Compile()();
    return string.Format("{0} - {1}", name, value);
}

использование:

Meth(() => YourObject.Property);

Ответ 5

Просто добавьте ответы выше. Вы также можете сделать простой флаг для направления заказа.

public class Processor
{
    public List<SortableItem> SortableItems { get; set; }

    public Processor()
    {
        SortableItems = new List<SortableItem>();
        SortableItems.Add(new SortableItem { PropA = "b" });
        SortableItems.Add(new SortableItem { PropA = "a" });
        SortableItems.Add(new SortableItem { PropA = "c" });
    }

    public void SortItems(Func<SortableItem, IComparable> keySelector, bool isAscending)
    {
        if(isAscending)
            SortableItems = SortableItems.OrderBy(keySelector).ToList();
        else
            SortableItems = SortableItems.OrderByDescending(keySelector).ToList();
    }
}

Ответ 6

Отличное решение здесь...

Передача свойств по ссылке в С#

void GetString<T>(string input, T target, Expression<Func<T, string>> outExpr)
{
    if (!string.IsNullOrEmpty(input))
    {
        var expr = (MemberExpression) outExpr.Body;
        var prop = (PropertyInfo) expr.Member;
        prop.SetValue(target, input, null);
    }
}

void Main()
{
    var person = new Person();
    GetString("test", person, x => x.Name);
    Debug.Assert(person.Name == "test");
}