将属性本身传递给 C# 中的参数
Posted
技术标签:
【中文标题】将属性本身传递给 C# 中的参数【英文标题】:Pass property itself to function as parameter in C# 【发布时间】:2012-06-26 02:10:14 【问题描述】:我正在寻找一种将属性本身传递给函数的方法。不是财产价值。函数事先并不知道将使用哪个属性进行排序。此示例中最简单的方法是:使用不同的参数类型创建 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 属性的传递以进行进一步处理。使用恕我直言的最佳选择将是(或类似的东西):
vehicles = sortBy(vehicles, Class1.maxSpeed);
【问题讨论】:
首先如何选择用于排序的属性? How can I pass a property of a class as a parameter of a method? 的可能重复项 【参考方案1】:你为什么不使用 Linq 呢?喜欢:
vehicles.OrderBy(v => v.maxSpeed).ToList();
【讨论】:
其他类将使用Processor
。他们不应该看到vehicles
。另外sortBy
会有更多的逻辑(升序/降序/一些过滤)...
那我觉得你应该看看上面@olivier 的回答,关于编写自己的扩展方法(添加过滤等)【参考方案2】:
您可以将属性访问器传递给方法。
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[]
和许多其他集合一样。
到目前为止,我已经展示了如何读取属性。如果方法需要设置一个属性,你也需要传递一个 setter 委托
void ReadAndWriteProperty(Func<Class1, T> getProp, Action<Class1, T> setProp)
其中T
是属性的类型。
【讨论】:
这个方法和 LINQ 的 OrderBy 有什么不同吗? @Chris Gessler:是的,如果源集合是null
或其Count
是0
,则返回null
,否则返回List<T>
。如果源是null
,LINQ 的OrderBy
将引发异常,否则返回IEnumerable<T>
。我不知道这种方法对其他人是否真的有用,但 OP 显然需要它。【参考方案3】:
您可以使用 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");
用法:
DoSomething(() => this.MyProperty);
【讨论】:
如果您需要获取有关属性的更多信息,例如属性名称(在实现INotifyPropertyChanged
时很有用),您可以使用此方法。但是,在这种情况下这样做有点过头了,因为返回属性值就足够了。【参考方案4】:
只是从上面的答案中添加。您也可以为订单方向做一个简单的标志。
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();
【讨论】:
【参考方案5】:我发现@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);
【讨论】:
【参考方案6】:这里的解决方案很好......
Passing properties by reference in 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");
【讨论】:
【参考方案7】:我想给出一个简单易懂的答案。
函数的参数是这样的:System.Func<class, type of the property>
我们像这样传递属性:Function(x => x.Property);
代码如下:
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);
【讨论】:
以上是关于将属性本身传递给 C# 中的参数的主要内容,如果未能解决你的问题,请参考以下文章