[英]Pass property itself to function as parameter in C#
我正在尋找一種將屬性本身傳遞給函數的方法。 不是財產價值。 函數事先不知道哪個屬性將用於排序。 此示例中最簡單的方法是:創建 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);
您可以將屬性訪問器傳遞給該方法。
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
是屬性的類型。
您可以使用 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);
我發現@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);
很棒的解決方案在這里...
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");
}
為什么不為此使用 Linq? 像:
vehicles.OrderBy(v => v.maxSpeed).ToList();
只是從上面的答案中添加。 您還可以為訂單方向做一個簡單的標志。
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();
}
}
我想給出一個簡單易懂的答案。
函數的參數是這樣的: 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);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.