简体   繁体   English

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

[英]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.此示例中最简单的方法是:创建 4 个具有不同参数类型的覆盖。 Other way is using of typeof() inside function.另一种方法是在函数内部使用typeof() Both these ways are unacceptable when Class1 has hundreds properties.当 Class1 有数百个属性时,这两种方式都是不可接受的。 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.请建议更优雅的方法来实现将 Class1 属性传递给函数以进行进一步处理。 The best option for usage IMHO will be (or something like this):使用恕我直言的最佳选择是(或类似的东西):

vehicles = sortBy(vehicles, Class1.maxSpeed);

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 Count property它必须具有Count属性
  2. It must be an IEnumerable<T> in order to be able to apply the LINQ method OrderBy .它必须是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 T is the type of the property.其中T是属性的类型。

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

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

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

Why don't you use Linq for this?为什么不为此使用 Linq? Like:像:

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

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

I would like to give a simple, easy to understand answer.我想给出一个简单易懂的答案。

Function's parameter is this: System.Func<class, type of the property>函数的参数是这样的: System.Func<class, type of the property>

And we pass the Property like this: Function(x => x.Property);然后我们像这样传递属性: Function(x => x.Property);

Here is the code:这是代码:

class HDNData
{
    private int m_myInt;
    
    public int MyInt
    {
        get { return m_myInt; }
    }
    
    public void ChangeHDNData()
    {
        if (m_myInt == 0)
            m_myInt = 69;
        else
            m_myInt = 0;
    }
}

static class HDNTest
{
    private static HDNData m_data = new HDNData();
    
    public static void ChangeHDNData()
    {
        m_data.ChangeHDNData();
    }
    
    public static void HDNPrint(System.Func<HDNData, int> dataProperty)
    {
        Console.WriteLine(dataProperty(m_data));//Print to console the dataProperty (type int) of m_data
    }
}

//******Usage******
HDNTest.ChangeHDNData();
//This is what you want: Pass property itself (which is MyInt) to function as parameter in C#
HDNTest.HDNPrint(x => x.MyInt);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM