繁体   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