6

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

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' 来检查是否存在具有客户编写的信息的对象,如果不存在,则将新值插入列表中?

4

3 回答 3

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 { ... });
于 2012-11-14T06:42:43.697 回答
0

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

因此,根据问题示例中的某些细节:

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

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

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

    lst.Add(data);
}

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

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

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

此外,在您的示例中使用 Expression< Func<...>> 根本没有帮助(正如有人建议的那样),因为您无论如何都在使用 List (只有在使用 IQueryable 等时才值得)

于 2013-01-17T10:02:21.427 回答
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为表示添加。

于 2012-11-14T13:24:05.723 回答