簡體   English   中英

對List的每個項執行自定義操作<T>

[英]Execute a custom operation on each item of a List<T>

我想對列表的成員進行自定義操作,並且能夠指定我將執行它的屬性,但是我很難找到將結果分配回屬性的正確語法。

示例:

我有一個術語列表,如下面的術語,並希望規范化他們的“頻率”。

public class Term
{
    public string Name { get; set; }
    public double Frequency { get; set; }
    public double Weight { get; set; }
}

使用這樣的語法我應該能夠指定我正在進行操作的屬性:

List<Term> list = Normalize(artist.Terms, s => s.Frequency);

(這里是'Term'上的'Frequency',但我應該可以在任何類型的任何屬性上執行此操作,屬性類型將始終為double)

這就是我精心制作但我無法找到如何執行操作,也沒有將結果分配回屬性:

private static List<T> Normalize<T>(List<T> elements, Func<T, double> func)
{
    List<T> list = new List<T>();
    double fMin = elements.Min(func);
    double fMax = elements.Max(func);
    double fDelta = fMax - fMin;
    double fInv = 1.0d / fDelta;
    for (int i = 0; i < elements.Count; i++)
    {
        T t = elements[i];

        // What should I do from here ?
        //double invoke = func.Invoke(term);
        //term.Frequency = (term.Frequency - fMin) * fInv;
     }
    return list;
}

你會如何實現這一目標?

如果要避免使用表達式和反射,可以簡單地同時提供getter函數和setter函數。 我也稍微更新了方法,因為它會改變 原始列表中的對象,所以我認為創建和返回新列表並不明智; API會具有欺騙性。 (如果需要,你可以輕松切換回來)

private static void Normalize<T>(List<T> elements, Func<T, double> getter, Action<T, double> setter)
{
    double fMin = elements.Min(getter);
    double fMax = elements.Max(getter);
    double fDelta = fMax - fMin;
    double fInv = 1.0d / fDelta;
    for (int i = 0; i < elements.Count; i++)
    {
        T t = elements[i];

        double initialValue = getter(t);
        double newValue = (initialValue - fMin) * fInv;
        setter(t, newValue);
    }
}

使用方式如下:

Normalize(terms, t => t.Frequency, (t, normalizedFrequency) => t.Frequency = normalizedFrequency);

當然,很容易更新為擴展方法,因此它可以像以下一樣使用:

terms.Normalize(t => t.Frequency, (t, normalizedFrequency) => t.Frequency = normalizedFrequency);

通過Normalize簽名中的這一更改,很明顯您正在更改 現有列表而不是生成新列表。 使用舊簽名,看起來您將保留舊列表和未觸及的對象,但事實並非如此。

您可以使用Expression來獲取屬性的句柄:

private static List<T> Normalize<T>(List<T> elements, Expression<Func<T, double>> func)
{
    //...
    var expr = (MemberExpression)func.Body;
    var property = expr.Member as PropertyInfo;
    if (property != null)
        property.SetValue(/* element */, /* new value */);
    //...
}

此外,我建議使用IEnumerable 這更靈活,可以隨時轉換為列表:

 private static IEnumerable<T> Normalize(...)
 {
     foreach(...)
     {
         yield return ...;
     }
 }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM