将属性本身传递为 C# 中的参数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11178864/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 16:53:25  来源:igfitidea点击:

Pass property itself to function as parameter in C#

c#propertiesparameter-passing

提问by Ivy Growing

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:

我正在寻找一种将属性本身传递给函数的方法。不是财产价值。函数事先不知道哪个属性将用于排序。本例中最简单的方法是:使用不同的参数类型创建 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");
}

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):

我不喜欢这种方法,因为在将字符串传递给处理函数时存在“人为错误”的风险。当字符串由代码的其他部分生成时,这将变得更加丑陋。请建议更优雅的方法来实现 Class1 属性的传递以进行进一步处理。使用恕我直言的最佳选择将是(或类似的东西):

vehicles = sortBy(vehicles, Class1.maxSpeed);

采纳答案by Olivier Jacot-Descombes

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:

请注意,我将第一个参数声明为ICollection<T>因为它必须满足两个条件:

  1. It must have a Countproperty
  2. It must be an IEnumerable<T>in order to be able to apply the LINQ method OrderBy.
  1. 它必须有一个Count属性
  2. 它必须是一个IEnumerable<T>才能应用 LINQ 方法OrderBy

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

List<Class1>与许多其他集合一样,ICollection<T>它也是一个数组Person[]



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

到目前为止,我已经展示了如何读取属性。如果该方法需要设置一个属性,则还需要向它传递一个 setter 委托

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

Where Tis the type of the property.

T属性的类型在哪里。

回答by joakimbeng

Why don't you use Linq for this? Like:

为什么不使用 Linq 呢?喜欢:

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

回答by MatthiasG

You can use an lambda expression to pass property information:

您可以使用 lambda 表达式来传递属性信息:

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

Usage:

用法:

DoSomething(() => this.MyProperty);

回答by cubski

Just to add from the answers above. You can also do a simple flag for the order direction.

只是从上面的答案中添加。您还可以为订单方向做一个简单的标志。

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

回答by Matas Vaitkevicius

What I found missing from @MatthiasG's answer is how to get property value not just its name.

我发现@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);
}

use:

用:

Meth(() => YourObject.Property);

回答by Carter Medlin

Great solution over here...

很棒的解决方案在这里...

Passing properties by reference in C#

在 C# 中通过引用传递属性

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