Reputation: 161
I would like to code a function that can accomplish some check before insert a value into a List. For example:
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 )
}
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?
Upvotes: 6
Views: 1875
Reputation: 720
quick combination/change from above answers, with some comments: (my rep is too low to simply comment blush)
So, based on certain details in the question's example:
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?
1) I would definitely consider creating/using a generic extension specifically for checking for duplicates (as mentioned, a common operation) before adding to list (rather than open "check"), so could be something like this:
public static void AddIfDistinct<T>(this List<T> lst, T data, Func<T, bool> dupeCheck)
{
if (lst.Any(dupeCheck))
return;
lst.Add(data);
}
2) based on the requirement, "Any" is much clearer, semantically, than "All", in my opinion - we are checking for "any" duplicates, rather than checking that "all" current items are "not" duplicated... It might sound trivial, but I think its safe to say it is more immediately apparent. This obviously means the lambda you pass in would look like this (the change in semantics here mean you really have to get the extension method named well)
s => s.Name.Equals("John")
3) last comment, if its appropriate, you could also override some stuff on your class like "CompareTo" etc and create a really generic "AddToListIfUnique" etc
Also, using Expression< Func<...>> in your example would not help at all (as somebody suggested), as you're using List anyway (would only be worthwhile if you were using IQueryable etc)
Upvotes: 0
Reputation: 73163
For your own semantics you have an answer already to rely on. But to me the method naming is obfuscatory the more I think of it. AddIf
means add if any or add if all? In your case it is all. So you should be naming it better. AddIfAll
or something.
To add to a list if something doesn't exist is a common requirement and what I would suggest is something little more fleshed out (I believe) for your purpose which makes it easier from the caller side.
May be
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;
}
A small Contains
overload I prefer to use in my programs:
public static bool Contains<S, T>(this IEnumerable<S> lstObject,
Func<S, T> comparer, T valueToMatch)
{
return lstObject.Any(s => comparer(s).Equals(valueToMatch));
}
This avoids the hassle of writing the Equals
operator from our side every time.
You can call:
persons.AddIfNotContains(s => s.Name, "John", new Person { ... });
I think that makes the syntax much simpler.
I hope you're aware of the catch here. You can very well write
persons.AddIfNotContains(s => s.Name, "John", new Person { Name = "Serena", .. });
even when there exists already someone with the name Serena
because here you're checking for John
. If that's ok for you, well and good. A better implementation if I understand your problem correctly would be:
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;
}
Now you can call easily:
persons.AddIfTrulyNotContains(s => s.Name, new Person { Name = "John", .. });
This just checks for John
and adds if there's no John
in list. Additionally I have made return type to bool
to denote addition.
Upvotes: 0
Reputation: 236208
You need to make your method generic.
public static void AddIf<T>(this List<T> lst, Func<T, bool> check, T data)
{
if (!lst.All(check))
return;
lst.Add(data);
}
And usage like you wanted (all items should satisfy predicate):
persons.AddIf(s => !s.Name.Equals("John"), new Person { ... });
Upvotes: 11