If Element does not exist - c#

I have around a dozen solutions to this, but none seem to fit what I am trying to do. The XML file has elements that may not be in the file each time it is posted.
The trick is, the query is dependent upon a question value to get the answer value. Here is the code:
string otherphone = (
from e in contact.Descendants("DataElement")
where e.Element("QuestionName").Value == "other_phone"
select (string)e.Element("Answer").Value
).FirstOrDefault();
otherphone = (!String.IsNullOrEmpty(otherphone)) ? otherphone.Replace("'", "''") : null;
Under the "contact" collection, here are many elements named "DataElement", each with its own "QuestionName" and "Answer" elements, so I query to find the one where the element's QuestionName value is "other_phone", then I get the Answer value. Of course I will need to do this for each value I am seeking.
How can I code this to ignore the DataElement containing QuestionName with value of "other_phone" if it doesn't exist?

You can use Any method to check whether or not the elements exists :
if(contact.Descendants("DataElement")
.Any(e => (string)e.Element("QuestionName") == "other_phone"))
{
var otherPhone = (string)contact
.Descendants("DataElement")
.First(e => (string)e.Element("QuestionName") == "other_phone")
.Element("Answer");
}
Also, don't use Value property if you are using explicit cast.The point of explicit cast is avoid the possible exception if the element wasn't found.If you use both then before the cast, accessing the Value property will throw the exception.
Alternatively, you can also just use the FirstOrDefault method without Any, and perform a null-check:
var element = contact
.Descendants("DataElement")
.FirstOrDefault(e => (string)e.Element("QuestionName") == "other_phone");
if(element != null)
{
var otherPhone = (string)element.Element("Answer");
}

So you want to know if other_phone exists or not?
XElement otherPhone = contact.Descendants("QuestionName")
.FirstOrDefault(qn => ((string)qn) == "other_phone");
if (otherPhone == null)
{
// No question with "other_phone"
}
else
{
string answer = (string)otherPhone.Parent.Element("Answer");
}

Related

Find string in a List, if match, string = List name

So my gameobject string name contain an ID(first variable) in the List, since the List is a custom class with two variable. I want to switch the name gameobject name to the second
variable after comparing the first variable and returning True.
if (gameData_List.showing_my_loading_list.Any(s => anchor.name.Contains(s.guid.ToString())))
{
Debug.Log("Found)
}
The result show 4 found, but what I'm trying to do is after knowing that is true, change the anchor.name to s.SecondVarible.Tostring();
However, after I set the condition in the if,
I no longer have access to the (s) in the Debug.Log area.
I managed to solve it myself, thanks
var temp = gameData_List.showing_my_loading_list.Find(x => anchor.name.Contains(x.guid.ToString()));
if (temp != null)
{
anchor.name = temp.readable_guid;
Debug.Log("Changing Name");
}
If you do not want to split it into lines you could probably do something like
anchor.name = gameData_List.showing_my_loading_list.FirstOrDefault(s => anchor.name.Contains(s.guid.ToString()))?.readable_guid ?? anchor.name;
So this does
FirstOrDefault: Try to find an element s where the condition is matched or return default (= null for classes)
?.: If it is not null use the readable_guid, otherwise return null again
??: If the before is null use anchor.name (the old one) as fallback => change nothing
Of course this loses the ability to do more things when you found a valid element like your logging etc.
Alternatively, why not simply stick to a normal loop ;)
foreach(var s in gameData_List.showing_my_loading_list)
{
if(anchor.name.Contains(s.guid.ToString())
{
anchor.name = s.readable_guid;
Debug.Log("Changing Name");
break;
}
}
or with Linq again
foreach (var s in gameData_List.showing_my_loading_list.Where(s => anchor.name.Contains(s.guid.ToString())))
{
anchor.name = s.readable_guid;
Debug.Log("Changing Name");
break;
}
gameData_List.showing_my_loading_list.filter(s => anchor.name.Contains(s.guid.ToString())).each(() => {
Debug.Log("Found)
})

Determine if a property is an auto property

I'm trying to figure out if a property is an auto property i.e.
public int Foo { get; set; }
Stared for a while at PropertyDeclarationSyntax and IPropertySymbol but did not find anything.
Guess an alternative is an extension method that evaluates if get & set does not contain any statements is one way but it does not feel very elegant.
Check whether any of the AccessorDeclarationSyntaxes in the PropertyDeclarationSyntax's AccessorList have a non-null Body.
You can see this by looking at any property declaration using the Syntax Visualizer (from the Roslyn SDK extension).
This blog gives a good explanation:
In summary,
var isExplicitProperty = node
.DescendantNodesAndSelf()
.OfType<PropertyDeclarationSyntax>()
.Any(prop =>
{
if(prop.AccessorList != null)
{
return prop.AccessorList.Accessors
.Any(a => a.Body != null || a.ExpressionBody != null);
}
// readonly arrow property declaration
return true;
});
Based on the internal source code

Find elements by attribute name and its value using XDocument

Well, using .NET 3.5 and XDocument I am trying to find <table class='imgcr'> element. I created the code below but it crashes, of course, because e.Attribute("class") may be null. So... I have to put null check everywhere? This will double e.Attribute("class"). Not laconic solution at all.
XElement table =
d.Descendants("table").
SingleOrDefault(e => e.Attribute("class").Value == "imgcr");
If you are sure you exception is thrown because you table element may come without class attribute, then you could do this instead:
XElement table =
d.Descendants("table").
SingleOrDefault(e => ((string)e.Attribute("class")) == "imgcr");
In that case you are casting a null value to string, which is null at the end, so you are comparing null == "imgcr", what is false.
You can check this msdn page if you need more info about how to retrieve the value of an attribute. There you will find this affirmation:
You can cast an XAttribute to the desired type; the explicit
conversion operator then converts the contents of the element or
attribute to the specified type.
I guess this is quite short
XElement table =
d.Descendants("table").
SingleOrDefault(e => { var x = e.Attribute("class"); return x==null ? false: x.Value == "imgcr";});
this is shorter (but not much -- unless you can re-use t variable.)
XAttribute t = new XAttribute("class","");
XElement table =
d.Descendants("table").
SingleOrDefault(e => (e.Attribute("class") ?? t).Value == "imgcr");

Check if string already exist in Table

I want to check if the email that user entered already exist in Office table,take a look bellow what I have done so far, the problem is that officeEmail is always true, even though the entered email doesn't exist it's never returning NULL.
public static bool IsOfficeEmail(string email)
{
using (var data = Database)
{
data.ObjectTrackingEnabled = false;
var officeEmail = data.Offices.Where(a => a.Active && a.Email.Equals(email));
if (officeEmail != null)
return true;
}
return false;
}
Where will not return you null, but empty sequence, change it to:
var officeEmail = data.Offices.FirstOrDefault(a => a.Active && a.Email.Equals(email));
if (officeEmail != null)
return true;
FirstOrDefault will return default value (here null) it will not find queried value.
It is an option to use Any if you are not interested in email record:
public static bool IsOfficeEmail(string email)
{
using (var data = Database)
{
return data.Offices.Any(a => a.Active && a.Email.Equals(email))
}
}
You will not get email record if you will not use it anyway. Which approach you should use depends on what will you do with officeEmail, if you are just querying if it exists -> Any will be the best approach here. If you would like to get check for existing record and do something with it, FirstOrDefault will be better.
Alternativly if you really want to use .Where you can also check if the returned collection contains ANY elements:
if (officeMail.Any()) // ...
Or even shorter:
if (officeMail.Any(a => a.Active && a.Email.Equals(email))) // ...
If you want to ensure that there is exactly ONE item within your list matching your condition use .Single instead of .Any which will throw an exception if none or more then one item was found.
The actual reason for your check allways returning true is that .Where will return an enumerator even when no item matches the condition. Therefor the result is never null.

C# Elegant way to handle checking for an item in a collection

I've posted a code sample below. Firstly let me explain
termStore.Groups in the code below is a collection of Group Objects (The exact class is irrelevant).
Checking for null : if (termStore.Groups[groupName] == null) seems like a logical (clean) approach, but if the Groups collection is empty then an exception is produced.
using the termStore.Groups.Contains is not an option either because this expects a strong type i.e: .Contains(Group)... not .Contains(GroupName as string)
Can someone recommend a clean / generic way I can check for if an item exists in collection .
Thank you....
TermStore termStore = session.TermStores.Where(ts => ts.Name == termStoreName).FirstOrDefault();
if (termStore.Groups[groupName] == null)
{
termStore.CreateGroup(groupName);
termStore.CommitAll();
}
Update: The exact class Sharepoint Taxonomy Classes. http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.taxonomy.group.aspx
Update 2, the exact collection : http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.taxonomy.groupcollection.aspx
Microsoft.SharePoint.Taxonomy.GroupCollection implements IEnumerable<Group>, so a bit of LINQ is probably just what the doctor ordered:-
if(termStore.Groups.Any(x => x.Name == "MyGroup"))
{
// group contains at least one item matching the predicate.
}
else
{
// group contains no items matching the predicate.
}
You'll need to be using .NET 3.5 or better and add "using System.Linq;" to the top of your file.
Edit
If you don't have LINQ available, or if it offends you, or if you've genuinely profiled and found that iterating over Groups is killing performance compared to the string indexer, you could use GroupCollection.Count to avoid the error state:-
if (termStore.Groups.Count == 0 || termStore.Groups[groupName] == null)
{
// Group doesn't exist.
}
IEnumerable.Any(...) should work for your case:
termsStore.Groups.Any()
I think this is what you are looking for:
termStore.Groups.ContainsKey(groupName)
Checks that the key exists, doesn't throw an exception if it doesn't. This is assuming that Groups is a collection that implements IDictionary.
May be this
termStore.Any() && termStore.Groups.Any() && termStore.Groups[groupName] == null
Ok, 2nd attempt. If Groups doesn't contain the required ContainsKey method then you can write it yourself. Then you can just use ContainsKey in place of Contains.
static class GroupExtensions
{
public static bool ContainsKey(this Groups groups, string key)
{
try
{
if(groups[key] == null)
{
return false;
}
}
catch
{
return false;
}
return true;
}
}

Categories

Resources