I want to check if JArray.Children() is null in the foreach loop.
I can do:
if (jArrayJson == null)
{
return;
}
but I want to do it in the foreach.
This is the different things I have tried:
JArray jArrayJson = (JArray)token.SelectToken("text");
foreach (JToken item in jArrayJson?.Children() ?? Enumerable.Empty<T>()) // Wouldn't compile
foreach (JToken item in jArrayJson?.Children()) // This will fail and not stop a null value
I saw this post about exention method, but I could not integrate the metod:
Check for null in foreach loop
public static IList<T> OrEmptyIfNull<T>(this IList<T> source)
{
return source ?? Array.Empty<T>();
}
foreach (JToken item in jArrayJson?.Children().OrEmptyIfNull()) // Wouldn't compile
Apparently, Children() returns a custom JEnumerable type that is actually a struct, so cannot be null, which makes the null propagation awkward. So you could make this work using your first attempt, with a JToken in the type parameter (like Johnathan Barclay already suggested):
foreach (JToken item in jArrayJson?.Children() ?? Enumerable.Empty<JToken>())
{
}
Or I tweaked your extension method to work off a JToken itself:
public static JEnumerable<JToken> ChildrenOrEmptyIfNull(this JToken token)
{
if(token == null)
{
return new JEnumerable<JToken>();
}
return token.Children();
}
which you could use like:
foreach (JToken item in jArrayJson?.ChildrenOrEmptyIfNull())
{
}
Related
See this sample:
var list = new List<string?>();
foreach (string item in list.Where(i => i != null))
{
if (item.Length == 2)
{
...
}
}
In this sample, I get possible null reference in two places. The foreach variable and the dereferencing of Length in if. The second one I can easily fix by adding a dammit (null-forgiving) operator like this: item!.Length
Is there any way to do the same thing to the first one? I know that I can mark it as nullable string and check again but, I have already checked.
When you apply filtering using Where, you eliminate all null values, but this doesn't change the type of values.
All you need is to cast the results after filtering to the proper type:
foreach (string item in list.Where(i => i != null).Select(x => x!))
Unfortunately the Where predicate doesn't modify the caller's view of whether items in the enumerable are null or not.
The approach given by Dmitry involves additional runtime overhead due to the use of an extra Select call.
You can avoid that overhead via this extension method:
public static IEnumerable<T> WhereNotNull<T>(this IEnumerable<T?> source) where T : class
{
foreach (T? item in source)
{
if (item != null)
yield return item;
}
}
Your code then becomes:
foreach (string item in list.WhereNotNull())
{
if (item.Length == 2)
{
...
}
}
How do I create LINQ to call DoSomething() only once to reduce these duplicate codes? Note that there are some properties in nameValue which I don't need to do anything about it. DoSomething() is only applied for these 4 properties.
foreach (var nameValue in nameDetails.NameValue)
{
if (nameValue.FirstName != null)
{
DoSomething(nameValue.FirstName)
}
if (nameValue.MaidenName != null)
{
DoSomething(nameValue.MaidenName)
}
if (nameValue.MiddleName != null)
{
DoSomething(nameValue.MiddleName)
}
if (nameValue.Surname != null)
{
DoSomething(nameValue.Surname)
}
}
Move the condition into the function and you can write
foreach (var nameValue in nameDetails.NameValue)
{
DoSomethingMaybe(nameValue.FirstName);
DoSomethingMaybe(nameValue.MaidenName);
DoSomethingMaybe(nameValue.MiddleName);
DoSomethingMaybe(nameValue.Surname);
}
void DoSomethingMaybe(string value)
{
if (value != null)
{
DoSomething(value)
}
}
perfectly readable and no unnecessary overhead, no throwaway objects. Maybe not the answer you expect, but LINQ is not magic, that makes things better just be being there.
You may create an array of *names, then use SelectMany to flatten 2 dimensional array into IEnumerable<string> , e.g.:
var enumerable = nameDetails.NameValue.SelectMany(elem => new[]
{
elem.FirstName,
elem.MaidenName,
elem.MiddleName,
elem.Surname
}).Where(value => value != null);
foreach (var value in enumerable)
{
DoSomething(value);
}
My interpretation of your question is that you want to write DoSomething only once but still want to perform it more than once if more than one name part is not null.
You can refactor your code to this:
var names = nameDetails.NameValue
.SelectMany(nv => new string[] { nv.FirstName, nv.MaidenName, nv.MiddleName, nv.Surname })
.Where(name => name != null);
foreach (var name in names)
{
DoSomething(name);
}
This makes use of SelectMany which allows each item of the source enumerable to be mapped into multiple values which are then flattened into an enumerable of the mapped element value's type.
I'm recursively iterating through an object's properties using the following method:
void GetProps(object obj)
{
if (obj == null)
return;
var objType = obj.GetType();
var properties = objType.GetProperties();
foreach (var property in properties)
{
object value = property.GetValue(obj, null);
if (typeof(IEnumerable).IsAssignableFrom(property.PropertyType))
{
var enumerable = (IEnumerable)value;
foreach (object child in enumerable)
GetProps(child);
}
else
{
GetProps(value);
}
}
}
The object is very complex (over 30 classes). I'm getting a StackOverflowException when going deeper into the object at GetProps(value.
Is there a way to catch the exception and check why it's failing, and, solve the problem?
EDIT
I added a fail-safe at the top of the method:
if (visited.Contains(obj))
return;
visited.Add(obj);
The problem is not with circular references (which I don't have) but with property types such as DateTime, int and decimal. which was assuming they're primitive but the IsPrimitive property is false.
Can I differentiate between such types and my own classes?
A StackOverflowException can't be caught unless you threw it, because it indicates a fatal problem with your application.
Most likely this happens because you have a circular reference. I.e. an object that contains another object which contains a reference to the original object. There may be an arbitrary number of hierarchy levels between the two classes.
You need to implement some kind of mechanism to stop traversing an object that you already traversed, e.g. with the help of a hash set.
Here is an example not using recursion, which leverages Eric Lippert's explicit stack approach. I don't know if the behavior with strings is as you intended, but this may prevent your stack from blowing:
public static IEnumerable<object> GetPropertiesDepthFirst(object obj)
{
if (obj == null)
yield break;
var stack = new Stack<object>();
stack.Push(obj);
while (stack.Count > 0)
{
var current = stack.Pop();
yield return current;
var objType = current.GetType();
var properties = objType.GetProperties();
foreach (var property in properties)
{
object value = property.GetValue(current, null);
if (value == null)
continue;
if (typeof(IEnumerable).IsAssignableFrom(property.PropertyType))
{
var enumerable = (IEnumerable)value;
foreach (object child in enumerable)
stack.Push(child);
}
else
{
yield return value;
}
}
}
}
Also for IEnumerables with defined indexes, you may want to exclude Indexed Properties:
objType.GetProperties().Where(p => p.GetIndexParameters().Length == 0)
I have a collection of objects IEnumerable<object> obs.
I have another collection of objects IEnumerable<object> data.
For each ob in obs I need to find the first item in data that has the same value in a certain property as ob. For example I could be looking for the first item in data that has the same ToString() value as ob. When the first item where the property values match is found, I do something with the found data item and then I check the next ob in obs. If none is found, I throw an error.
Here is a naive approach:
foreach (object ob in obs)
{
foreach (object dataOb in data)
if (ob.ToString() == dataOb.ToString())
{
... // do something with dataOb
goto ContinueOuter;
}
throw new Exception("No matching data found.");
ContinueOuter: ;
}
The disadvantage is that I calculate dataOb.ToString() every time, which is unnecessary.
I could cache it:
IDictionary<object, string> dataToDataStr = new Dictionary<object, string>();
foreach (object dataObj in data) // collect all ToString values in advance
dataToDataStr.Add(dataObj, dataObj.ToString());
foreach (object ob in obs)
{
foreach (object dataOb in dataToDataStr.Keys)
if (ob.ToString() == dataToDataStr[dataOb])
{
... // do something with dataOb
goto ContinueOuter;
}
throw new Exception("No matching data found.");
ContinueOuter: ;
}
The disadvantage is that I calculate all ToString() values even though it might not be necessary. I might find all matching data objects in the first half of the data collection.
How can I build up the dataToDataStr dictionary (or any other enumerable data structure that lets me retrieve both the object and its only-once-calculated ToString value) lazily?
Here is code (mixed with pseudocode) of what I have in mind:
IDictionary<object, string> dataToDataStr = new Dictionary<object, string>();
object lastProcessedDataOb = null;
foreach (object ob in obs)
{
foreach (object dataOb in dataToDataStr.Keys)
if (ob.ToString() == dataToDataStr[dataOb])
{
... // do something with dataOb
goto ContinueOuter;
}
foreach (object dataOb in data STARTING AFTER lastProcessedDataOb)
// if lastProcessedDataOb == null, start with the first entry of data
{
dataToDataStr.Add(dataOb, dataOb.ToString();
lastProcessedDataOb = dataOb;
if (ob.ToString() == dataToDataStr[dataOb])
{
... // do something with dataOb
goto ContinueOuter;
}
}
throw new Exception("No matching data found.");
ContinueOuter: ;
}
I know it is easy if data was a LinkedList or any collection with indexed access (then I could store a linked list node or an index as lastProcessedDataOb), but it isn't - it is an IEnumerable. Maybe yield return can be used here?
If your collections are really large and you really don't want to evaluate ToString for each item of data, you could use the following approach:
Create cache of already calculated items
If certain item is found i cache - that's great, we have a match.
Otherwise - continue populating cache by iterating over data collection until we find a match. This can be efficiently be done with manually controlling **Enumerator** of data collection (instead of using foreach).
IEnumerable<object> obs;
IEnumerable<object> data;
Dictionary<string, object> dataCache = new Dictionary<string, object>();
var dataIterator = data.GetEnumerator();
foreach (var ob in obs)
{
var obText = ob.ToString();
object matchingDataItem = null;
if (!dataCache.TryGetValue(obText, out matchingDataItem))
{
while (dataIterator.MoveNext())
{
var currentData = dataIterator.Current;
var currentDataText = currentData.ToString();
if (!dataCache.ContainsKey(currentDataText)) // Handle the case when data collection contains duplicates
{
dataCache.Add(currentDataText, currentData);
if (currentDataText == obText)
{
matchingDataItem = currentData;
break;
}
}
}
}
if (matchingDataItem != null)
{
Console.WriteLine("Matching item found for " + obText);
}
else
{
throw new Exception("No matching data found.");
}
}
This way you can guarantee to iterate over data collection only to the point when all obs items are found and you won't evaluate ToString for each item more then once.
PS: I hope "ToString" is just for example and you have some complex calculations there, which is worth such complexities...
Totally forgot that LINQ uses lazy evaluation...
This should work (I use the new value tuple notation of C# 7):
IEnumerable<(object, string)> objStrPairs = data.Select(o => (o, o.ToString()));
foreach (object ob in obs)
{
foreach ((object, string) dataPair in objStrPairs)
if (ob.ToString() == objStrPairs.Item2)
{
... // do something with objStrPairs.Item1
goto ContinueOuter;
}
throw new Exception("No matching data found.");
ContinueOuter: ;
}
Ok this is what i am doing right now but i wonder are there any better approach to do it?
if (vrChildNode.SelectNodes("//href") != null)
foreach (var vrNodes in vrChildNode.SelectNodes("//href"))
{
}
As you can see i am actually querying 2 times. First for null check and second for foreach.
If i do the way below it throws error if there is no nodes
foreach (var vrNodes in vrChildNode.SelectNodes("//href"))
{
}
Thank you for answers
c# .net 4.5
You can create an extension method to do the check and ensure the result is non-null:
public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> source)
{
return source ?? Enumerable.Empty<T>();
}
Then you can write:
foreach (var vrNodes in vrChildNode.SelectNodes("//href").EmptyIfNull())
{
}
The best and clearest way is to store it in a variable:
var nodes = vrChildNodes.SelectNodes("//href");
if (nodes != null)
foreach (var vrNodes in nodes)
{
}
A less clean and less obvious way, but a single liner:
foreach (var vrNodes in vrChildNodes.SelectNodes("//href") ?? Enumerable.Empty<nodeType>)
{
}
I'd really suggest you to do the first. Everyone will see what you meant with a single look. With the second approach, you really first have to look and think about what the purpose is (I think it is already horrible result that SelectNodes can return null, but I know that's not in your hand).
If you like you can also create an extension method to do a check for you:
public static IEnumerable<nodeType> SelectNodesSafe(this typeOfvrChildNodes t, string selector)
{
var res = t.SelectNodes(selector);
if (res == null)
return Enumerable.Empty<nodeType>();
else // Redundant else
return res;
}
foreach (var vrNodes in vrChildNode.SelectNodes("//href") ?? Enumerable.Empty<type>)
{
}