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

我正在寻找一种方法将属性本身传递给一个函数。 不是财产的价值。 函数事先不知道哪个属性将用于排序。 此示例中最简单的方法是:使用不同的参数类型创建4个覆盖。 其他方法是使用typeof()内部函数。 当Class1具有数百个属性时,这两种方式都是不可接受的。 到目前为止我找到了以下方法:

 class Class1 { string vehName; int maxSpeed; int fuelCapacity; bool isFlying; } class Processor { List vehicles = null; Processor(List input) { vehicles = input; } List sortBy(List 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 vehicles = new List(); // ... fill the list Processor pr = new Processor(vehicles); List sorted = pr.sortBy("maxSpeed"); } 

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

 vehicles = sortBy(vehicles, Class1.maxSpeed); 

您可以将属性访问器传递给该方法。

 List SortBy(List toSort, Func 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 OrderByAsListOrNull( this ICollection collection, Func keySelector) if (collection != null && collection.Count > 0) { return collection .OrderBy(x => keySelector(x)) .ToList(); } return null; } } 

现在你可以像这样排序

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

但是也

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

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

  1. 它必须具有Count属性
  2. 它必须是IEnumerable才能应用LINQ方法OrderBy

List是一个ICollection但也是一个数组Person[]和许多其他集合一样。


到目前为止,我已经展示了如何阅读房产。 如果方法需要设置属性,则还需要将其传递给setter委托

 void ReadAndWriteProperty(Func getProp, Action setProp) 

其中T是财产的类型。

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

 void DoSomething(Expression> 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); 

我从@ MatthiasG的答案中找不到的是如何获得属性值而不仅仅是它的名称。

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

使用:

 Meth(() => YourObject.Property); 

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

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

这里很棒的解决方案……

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

 void GetString(string input, T target, Expression> 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"); } 

只是从上面的答案添加。 您还可以为订单方向执行简单的标记。

 public class Processor { public List SortableItems { get; set; } public Processor() { SortableItems = new List(); SortableItems.Add(new SortableItem { PropA = "b" }); SortableItems.Add(new SortableItem { PropA = "a" }); SortableItems.Add(new SortableItem { PropA = "c" }); } public void SortItems(Func keySelector, bool isAscending) { if(isAscending) SortableItems = SortableItems.OrderBy(keySelector).ToList(); else SortableItems = SortableItems.OrderByDescending(keySelector).ToList(); } }