Let's suppose I have a very simple IEnumerable that looks like this:
IEnumerable<string> foo = new[] { "Apple", null, "Orange" };
I would like to check if it contains a null item. Based on what I found with Google, I can do this as follows:
bool containsNull = foo.Any(item => item == null);
What about the Enumerable.Contains method? The following seems pretty obvious to me, but I've never seen it this way:
bool containsNull = foo.Contains(null);
Is there any problem with the previous expression that results in the Enumerable.Any method used instead?
It's true, in most of the cases Contains(null) will do the work. But there is a vulnerability for ArgumentNullException. An example can be:
string foo = "foo";
bool containsNull = foo.Contains(null); //throws exception
In your case, you've already set the generic type as string so it is safe to use Contains.
The "Contains" operator checks whether a specified element exists in the collection or not and returns a boolean.
"Any" checks whether any element satisfy given condition or not? In the following example, Any operation is used to check whether any student is teen ager or not.
In this case is better use "ANY"
yo can to visit https://www.tutorialsteacher.com/linq/linq-quantifier-operators
Related
So I've got a collection of structs (it's actually a WCF datacontract but I'm presuming this has no bearing here).
List<OptionalExtra> OptionalExtras;
OptionalExtra is a struct.
public partial struct OptionalExtra
Now I'm running the below statement:
OptionalExtra multiOptExtra = OptionalExtras.Where(w => w.Code == optExtra.Code).FirstOrDefault();
if (multiOptExtra != null)
{
}
Now this won't compile:
the operator != cannot be applied to opperands of type OptionalExtra
and '<null>'
After a little googling I realised it's because OptionalExtra is a struct. Which I believe is not nullable unless defined as a nullable type?
So my question is, if my where statement returns no results what will be the outcome of the FirstOrDefault call? Will it thrown an exception?
Incidently this should never happen but better safe than sorry.
If your collection is empty, FirstOrDefault will return default(OptionalExtras). The default value of a struct is the struct with all its values in turn default initialized (i.e. zero, null, etc.).
If you assume that there will be an element and your code doesn't work with an empty collection, Use First() instead, since that will throw an exception when your collection is empty. It's generally better to fail fast than to return wrong data.
If you cannot assume that there will be an element, but also cannot deal with struct default initialization, you might make the structs in the collection a nullable value type, for example as follows:
OptionalExtras
.Where(w => w.Code == optExtra.Code)
.Cast<OptionalExtra?>()
.FirstOrDefault();
This way you can get a null return even for a struct. The key idea here is to extend the set of possible values to include something other than an OptionalExtra to allow detection of an empty list. If you don't like nullables, you could instead use a Maybe<> implementation (not a .NET builtin), or use an empty-or-singleton list (e.g. .Take(1).ToArray(). However, a nullable struct is likely your best bet.
TL;DR;
.FirstOrDefault<T>() returns default(T) if the sequence is empty
Use .First() instead if you assume the list is non-empty.
Cast to nullable and then use .FirstOrDefault<T>() when you cannot assume the list is non-empty.
As others have said, the result of your code when no elements match will be:
default( OptionalExtra )
If you want a null returned, you can cast your list to OptionalExtra?
OptionalExtra? multiOptExtra = OptionalExtras.Cast<OptionalExtra?>().Where( ...
You can then test for null
If default(OptionExtra) is still a valid value, it's better to change your code to this
var results = OptionalExtras.Where(w => w.Code == optExtra.Code).Take(1).ToList();
if (results.Any()) {
multiOptExtra = results[0]
}
The result will be the default value of your struct, e.g. default(OptionalExtras).
Whereas for a reference type the default value is null.
its provide you defualt value for your structure like as below
int[] numbers = { };
int first = numbers.FirstOrDefault();
Console.WriteLine(first);//this print 0 as output
other option to handle is make use of default value like as below
List<int> months = new List<int> { };
// Setting the default value to 1 by using DefaultIfEmpty() in the query.
int firstMonth2 = months.DefaultIfEmpty(1).First();
Console.WriteLine("The value of the firstMonth2 variable is {0}", firstMonth2);
If you want to check for null, use System.Nullable collection:
var OptionalExtras = new List<OptionalExtra?>();
/* Add some values */
var extras = OptionalExtras.FirstOrDefault(oe => oe.Value.Code == "code");
if (extras != null)
{
Console.WriteLine(extras.Value.Code);
}
Note that you have to use Value to access the element.
Assuming Code is a string for the purposes of my answer, you should be able just to test that value for its default.
OptionalExtra multiOptExtra = OptionalExtras.Where(w => w.Code == optExtra.Code).FirstOrDefault();
if (multiOptExtra.Code != null)
{
}
viewModel.IsMember= Name.ToLower()
.Equals(_sessionModel.Groups[2].MemberGroup, StringComparison.OrdinalIgnoreCase);
Groups can contain only 3 and the Member group is in the 3rd item which is why I mentioned 2 as index. It works fine but when I write unit test without 0 and 1 items, it throw exception
System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
I think you should use LastOrDefault()
_sessionModel.Groups.LastOrDefault().MemberGroup
You don't mention what type contains MemberGroup, but let's say it's any type that derives from IFoo. So you need whatever item in the Group collection that has a MemberGroup property, meaning you need whatever item is castable to a IFoo. Thus you can use:
viewModel.IsMember = Name.ToLower()
.Equals
(
_sessionModel.Groups.OfType<IFoo>().Single().MemberGroup,
StringComparison.OrdinalIgnoreCase
);
If you're not sure if the Groups collection will contain an IFoo, you can use this code instead:
viewModel.IsMember = Name.ToLower()
.Equals
(
_sessionModel.Groups.OfType<IFoo>().SingleOrDefault()?.MemberGroup ?? null,
StringComparison.OrdinalIgnoreCase
);
This version will try to find an IFoo, but if it can't find any it'll behave as if MemberGroup was null, meaning that the comparison will probably return false. It might be clearer to write it like this:
bool IsMatch(sessionModel, name)
{
var groupToMatch = _sessionModel.Groups.OfType<IFoo>().SingleOrDefault();
if (groupToMatch != null)
{
if (Name.Equals(groupToMatch.MemberGroup, StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
return false;
}
viewModel.IsMember = IsMatch(_sessionModel, Name);
The null-conditional operator is very useful when the method belongs to the object in question, but what if the object in question is an argument? For example, can this be shortened?
var someList = new List<SomeType>();
if (anotherList.Find(somePredicate) != null)
{
someList.Add(anotherList.Find(somePredicate))
}
One solution I thought of was to use an extension method like below:
public static void AddTo<T>(this T item, List<T> list)
{
list.Add(item);
}
With that the first code block can be reduced to:
var someList = new List<SomeType>();
anotherList.Find(somePredicate)?.AddTo(someList);
But this solution is specific to this example (i.e. adding an object to a list if it's not null). Is there a general way to indicate that if a parameter is null, the method should not be run?
Never do this
var someList = new List<SomeType>();
if (anotherList.Find(somePredicate) != null)
{
someList.Add(anotherList.Find(somePredicate))
}
this will search the list twice which is unnecessary. use a temporary variable instead.
var someList = new List<SomeType>();
var find = anotherList.Find(somePredicate);
if (find != null) someList.Add(find);
Is there a general way to indicate that if a parameter is null, the method should not be run?
Currently there is no such feature. how ever there are other alternatives that work better like in other answers provided.
You could also use just:
var someList = new List<SomeType>();
someList.AddRange(anotherList.Where(somePredicate));
In your case you probably need to make sure that your predicate only finds at max one element.
TLDR: Not yet.
The team plans to implement a functionality into the language, that would do this exact thing. It would look something like this:
someList.Add(anotherList.Find(somePredicate) ?? return);
In which the ?? return checks whether the first argument is null, and if it is, than it returns. (Or you could write break if that is what you want)
I am not sure if this is a thing they are working on at the moment, and if it will be included in the next version of C#, but would go a long way if it is going to be.
This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 5 years ago.
I am trying to get a list item that contains a certain string and I am using this code:
string myListLine= myList.FirstOrDefault(stringToCheck => stringToCheck.Contains("mystring "));
All works well but if the list does not contain a particular string it throws an error:
object reference not set to an instance of an object
I think that I should somehow validate if the string first exists but not sure what would be the best approach.
if the list does not contain a particular string it throws an error:
That is not correct. The exception is thrown, because you have a null value inside your list! If all of your items in the list are valid strings then there will be no exception thrown. In this case FirstOrDefault will simply return null.
I think that I should somehow validate if the string first exists
You can check whether it is null the oldscool way first and combine it with an logical AND && with the Contains method
string myListLine= myList.FirstOrDefault(stringToCheck =>
stringToCheck != null && stringToCheck.Contains("mystring "));
This way the second Contains will not be evaluated if the first condition evaluates to FALSE
You can use the safe navigation operator and the null-coalescing operator to fix this:
System.Collections.Generic.List<string> myList = new System.Collections.Generic.List<string> { null, "Test123" };
string myListLine = myList.FirstOrDefault(stringToCheck => stringToCheck?.Contains("mystring ") ?? false);
The problem occurs if you're calling a method on a null list entry.
Note: If the list is empty FirstOrDefault returns null.
Hope that helps.
Your code simply goes through myList, for each item, it checks if it contains "mystring ".
Only reason you may get a null reference while running that line is your list myList is null. It wouldn't get any error if it is empty.
if you get a null reference after that line, that would mean that myListLine is null, which would mean myList did not contain any items that matched "mystring ".
To make sure you do not get a null reference error with myListLine you should check if it is null before accessing it by using something like this;
if( myListLine != null ){
<Do something to myListLine>
} else {
<list doesnt contain the correct string, alert user.>
}
I think this sample code of mine is one of the safest way by accessing the myList object. If it is null then return an indicator that value was not found or empty.
List<string> myList = new List<string>()
{
"name","adress","phoneNumber"
};
myList.RemoveAll(item => item == null);
string myListLine = myList.FirstOrDefault(stringToCheck => stringToCheck.Contains("myString")) ?? "Not found/Empty";
A variation:
var myList = new List<string>(){"foo","Bar", null,"the mystring"};
string myListLine = myList.FirstOrDefault(s => s == null? false : s.Contains("mystring"));
Same notes as already mentioned regarding FirstOrDefault being null if empty list or no match (does not Contains)
I have an interesting scenario in which I've built a validation checking system that maintains a series of requirements in the form List<Tuple<Func<bool>, string>> where the Func should return true if validation failed and false otherwise. The string is a corresponding rejection description that describes the condition should the test fail.
In more simple tests like the following the validation system is quite simple:
validationChecks.Add(Tuple.Create<Func<bool>, string>(() =>
value1 == requiredValue, "value 1 did not have the required value"));
I'm struggling to understand the scope of variables within the lambda for the Func in a more advanced scenario in which the rejection string is calculated in a call to another part of the system. The scenario looks something like this:
string rejectionString = null;
validationChecks.Add(Tuple.Create<Func<bool>, string>(() => {
rejectionString = CallToAnotherMethodThatReturnsString(parameter);
if (rejectionString != null) {
return true;
} else {
return false;
}
}, rejectionString));
EDIT: As observed through testing, when this check fails the rejectionString from the Tuple is still null. I want the rejectionString that was generated by the CallToAnotherMethod to be used instead, is there any way I can do this using ref or otherwise? I need the Func's code to be able to affect the value of the string inside Item2 of the Tuple.
The problem is that the code inside of CallToAnotherMethodThatReturnsString might be code that I only want executed ONCE. However should the check fail I want to use the string that would have been returned from it as my rejection description in the Tuple. I'm unable to tell at this point what the effect of my use of rejectionString in this second example will accomplish? Will rejectionString inside the Tuple always be null? Or if CallToAnotherMethodThatReturnsString returns a different value will it be updated?
Just an idea that might work. I think if you change your second Tuple parameter to a Func that returns string instead of string value, you could come close to what you need.
string rejectionString = null;
validationChecks.Add(Tuple.Create<Func<bool>, Func<string>>(() =>
{
rejectionString = CallToAnotherMethodThatReturnsString(parameter);
if (rejectionString != null) {
return true;
} else {return false;}
},
()=>rejectionString));
In the first case your validation check would be set as
validationChecks.Add(Tuple.Create<Func<bool>, Func<string>>(() => value1 == requiredValue, ()=>"value 1 did not have the required value"));
And your validation is logic is then
if(validationChecks[0].Item1()==false)
var error = validationChecks[0].Item2();