传递属性本身作为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
因为它必须满足两个条件:
- 它必须具有
Count
属性 - 它必须是
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(); } }