扩展方法,T的Func和T的列表

时间:2012-11-14 06:39:18

标签: c# generics lambda extension-methods

我想编写一个函数,可以在将值插入List之前完成一些检查。 例如:

class Person {
    public string Name { get; set; }
    public int Value { get; set; }
    public Guid Id { get; set; }
}
-------
var persons = new List<Person>();
// add a new person if John doesn't exist
persons.AddIf(s => !s.Name.Equals("John"), new Person { ... });
----
public static void AddIf(this List<T> lst, Func<T, bool> check, T data)
{
     // how can I use the Func 'check' to check if exist an object with the
     // information that the client wrote and, if not exists, insert the new value
     // into the list???
     if ( check )
}

如何使用Func'check'检查是否存在具有客户端编写信息的对象,如果不存在,则将新值插入列表中?

3 个答案:

答案 0 :(得分:11)

您需要使您的方法通用。

public static void AddIf<T>(this List<T> lst, Func<T, bool> check, T data)
{
    if (!lst.All(check))
        return;

    lst.Add(data);
}

和你想要的用法(所有项目都应该满足谓词):

persons.AddIf(s => !s.Name.Equals("John"), new Person { ... });

答案 1 :(得分:0)

对于你自己的语义,你有一个可以依赖的答案。但对我来说,这个方法命名是混淆的,我想的就越多。 AddIf表示是否添加或添加全部?在你的情况下,这就是全部。所以你应该更好地命名它。 AddIfAll或其他什么。

要添加到列表中,如果不存在某些内容是一个常见的要求,我建议的是为了您的目的而更加充实(我相信),这使得来电者更容易。

可能是

public static bool AddIfNotContains<S, T>(this ICollection<S> lstObject, 
                                          Func<S, T> selector, T valueToMatch,
                                          S objectToAdd)
{
    if (lstObject.Contains(selector, valueToMatch))
        return false;

    lstObject.Add(objectToAdd);
    return true;
}

我更喜欢在我的程序中使用的Contains超载:

public static bool Contains<S, T>(this IEnumerable<S> lstObject, 
                                  Func<S, T> comparer, T valueToMatch)
{
    return lstObject.Any(s => comparer(s).Equals(valueToMatch));
}

这避免了每次都从我们这边写Equals操作员的麻烦。

您可以致电:

persons.AddIfNotContains(s => s.Name, "John", new Person { ... });

我认为这使语法更简单。

注意:

我希望你知道这里的问题。你可以写得很好

persons.AddIfNotContains(s => s.Name, "John", new Person { Name = "Serena", .. });

即使已存在名为Serena 的人,因为您正在检查John。如果那对你好,那么好。 如果我正确理解您的问题,那么更好的实施方式是

public static bool AddIfTrulyNotContains<S, T>(this ICollection<S> lstObject, 
                                               Func<S, T> selector, S objectToAdd)
{
    if (lstObject.Contains(selector, selector(objectToAdd)))
        return false;

    lstObject.Add(objectToAdd);
    return true;
}

现在你可以轻松打电话了:

persons.AddIfTrulyNotContains(s => s.Name, new Person { Name = "John", .. });

这只会检查John,如果列表中没有John则会添加。另外,我已将返回类型设为bool以表示添加。

答案 2 :(得分:0)

快速组合/更改上述答案,并附上一些评论:(我的代表太低而不能简单地评论脸红

所以,基于问题示例中的某些细节:

  

如何使用Func'check'检查是否存在具有的对象   客户编写的信息,如果不存在,则插入新信息   值列入名单?

1)我肯定会考虑创建/使用通用扩展,专门用于在添加到列表(而不是打开“check”)之前检查重复项(如所提到的,常见操作),所以可能是这样的:

public static void AddIfDistinct<T>(this List<T> lst, T data, Func<T, bool> dupeCheck)
{
    if (lst.Any(dupeCheck))
        return;

    lst.Add(data);
}

2)根据要求,“Any”在语义上比“All”更清晰,在我看来 - 我们正在检查“任何”重复,而不是检查“所有”当前项目是否“不”重复......这可能听起来微不足道,但我认为可以说它更为明显。这显然意味着你传入的lambda看起来像这样(这里的语义变化意味着你必须得到名为well的扩展方法)

s => s.Name.Equals("John")

3)最后评论,如果合适的话,你也可以覆盖你的课上的一些东西,如“CompareTo”等,并创建一个非常通用的“AddToListIfUnique”等

此外,使用表达式&lt; FUNC&LT; ...&GT;&GT;在你的例子中根本没有帮助(正如有人建议的那样),因为你无论如何都在使用List(只有你使用IQueryable等时才值得)