How can I refactor these two lines to one statement? - c#

I have the following code:
// TryGetAttributeValue returns string value or null if attribute not found
var attribute = element.TryGetAttributeValue("bgimage");
// Convert attribute to int if not null
if (attribute != null) BgImage = convert.ToInt32(attribute);
The thing I don't like is that I have to create a temp variable, attribute, in order to test if it's null or not, and then assign the value to the BgImage variable, which is a nullable int.
I was hoping I could figure out a way to write it all on one line, but I cannot figure a way. I even tried using a ternary statement, but got nowhere:
if (element.TryGetAttributeValue("bgimage") != null) ? BgImage = //Convert result to int : else null;
Realistically, my original two lines of code do the job. I was just hoping to pare it down to one line. But, if anyone knows how to do what I'm trying to accomplish, I'd love to learn how.

I recommend you to use Linq to Xml for parsing Xml (according to your attempt you have BgImage as nullable integer):
BgImage = (int?)element.Attribute("bgimage");
You also can assign some default value if BgImage is not nullable:
BgImage = (int?)element.Attribute("bgimage") ?? 0;

Assuming TryGetAttributeValue returns a string you could do something like
BgImage = convert.ToInt32(element.TryGetAttributeValue("bgimage") ?? "-1")
This would set BgImage to a default value (-1) if the attribute does not exist. If you would prefer to have BgImage set to null when there is no bgimage attribute then it gets a little bit clunkier
BgImage = element.TryGetAttributeValue("bgimage") != null ?
convert.ToInt32(element.TryGetAttributeValue("bgimage")) : (int?)null;

Related

Nullable record structs in C# [duplicate]

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)
{
}

Proper null check

I am instantiating an Associate object and assigning properties to it from txtboxes inside of my main form. What is the best practice for null checking? Is it to check each and every property with an if statement before I assign it or is there something a bit better? Here is my code:
Associate updateAssociate = new Associate();
updateAssociate.AssocID = txtAssocId.Text;
updateAssociate.FirstName = txtFname.Text;
updateAssociate.LastName = txtLname.Text;
updateAssociate.HireDate = Convert.ToDateTime(txtHireDate.Text);
updateAssociate.ContractEndDate = Convert.ToDateTime(txtContractEnd.Text);
updateAssociate.TerminationDate = Convert.ToDateTime(txtTerminationDate.Text);
updateAssociate.FullPartTimeID = cboFullPart.SelectedText;
updateAssociate.PrimaryRole = cboPRole.SelectedText;
Based on your comment to the question:
If it is a text box then it would be the .Text property I would want to check for null or blank values before I assign them to the object
You can use the null coalescing operator to check for null values when assigning like that:
updateAssociate.AssocID = txtAssocId.Text ?? string.Empty;
or:
updateAssociate.AssocID = txtAssocId.Text ?? someDefaultValue;
That way if txtAssocId.Text is null then you would assign your defined default to the object property instead of null.
Though I'm not entirely sure a TextBox's .Text property would ever be null instead of an empty string. Maybe you want to check for both?:
updateAssociate.AssocID = string.IsNullOrEmpty(txtAssocId.Text) ? someDefaultValue : txtAssocId.Text;
In C# 6 it would be null-conditional operator.
updateAssociate.AssocID = txtAssocId?.Text;
In prior versions of c# you can write a method to eliminate code duplication. Something like this:
public static T CheckNull<T>(Func<T> canBeNull) where T : class
{
try
{
return canBeNull();
}
catch (NullReferenceException)
{
return default(T);
}
}
And use it like this
updateAssociate.AssocID = CheckNull(() => txtAssocId.Text);
Then you can wrap any code that can throw a null reference into lambda, pass it to this method and no longer bother with it.

Conditions inside a C# Class

I have this below script in my Class.
aggrgt.Add(new PlainBrgDataSummaryChartAggrgt
{
label = m.label,
goal = m.goal,
groupCode = m.groupCode,
groupValue1 = m.groupValue1,
graphSwitch = m.graphSwitch,
orderByAsc = m.orderByAsc,
metricID = m.metricID,
scoreWk1 = metricscoreWk1.metricScore1,
});
The condition I want is when metricscoreWk1 is null, scoreWk1 = metricscoreWk1.metricScore1 is eliminated.
This may help you:
scoreWk1 = metricscoreWk1.metricScore1 ==null ? 0 : metricscoreWk1.metricScore1
That is, if the value of metricscoreWk1.metricScore1 is null 0(or else any default value) will be assigned else the original value will be assigned to scoreWk1
You can't put "" for Double, the closest analogue, INHO, is Double.NaN (Not A Number):
// Let's have Double.NaN for unknown/undefined etc. value
scoreWk1 = metricscoreWk1.metricScore1 ?? Double.NaN;
You could either:
Create the PlainBrgDataSummaryChartAggrgt object without setting the scoreWk1 field. If metricscoreWk1 is not null, you then set the field and you then add the object to the list.
If you have a setter for metricScore1, you could add a check wherein you ensure that metricscoreWk1 is not null. If it is, the value is not updated.
The second option would allow you to keep your current initialization structure, but the first is more explicit. Should you opt for the second approach, I'd recommend you document it.

How to return a null value from a database

I am trying to populate a combobox with a list my query returns. When I execute my program it gives me a specified cast is not valid error ( I have it execute on page load event). Every field in the database I have to work with can be null except the primary key. So I tried using DBNull.Value but it can't get my (int)reader fields to work. I have supplied my code below for a better understanding. How can I get my (int)reader's to work with my statements, so they can read when there is a null value?
CustData cd = new CustData();
cd.CustomerID = (int)reader["CustomerID"];
cd.Name = reader["Name"] != DBNull.Value ? reader["Name"].ToString() : string.Empty;
cd.ShippingAddress = reader["ShippingAddress"] != DBNull.Value ? reader["ShippingAddress"].ToString() : string.Empty;
cd.ShippingCity = reader["ShippingCity"] != DBNull.Value ? reader["ShippingCity"].ToString() : string.Empty;
cd.ShippingState = reader["ShippingState"] != DBNull.Value ? reader["ShippingState"].ToString() : string.Empty;
cd.ShippingZip = (int)reader["ShippingZip"];
cd.BillingAddress = reader["BillingAddress"] != DBNull.Value ? reader["BillingAddress"].ToString() : string.Empty;
cd.BillingCity = reader["BillingCity"] != DBNull.Value ? reader["BillingCity"].ToString() : string.Empty;
cd.BillingState = reader["BillingState"] != DBNull.Value ? reader["BillingState"].ToString() : string.Empty;
cd.BillingZip = (int)reader["BillingZip"];
cd.Territory = reader["Territory"] != DBNull.Value ? reader["Territory"].ToString() : string.Empty;
cd.Category = reader["Category"] != DBNull.Value ? reader["Category"].ToString() : string.Emptyy
That is because int is not nullable. You need to use int? or nullable<int> (long hand) to allow it to be an int OR a null value.
You can then use the usual .HasValue and .Value etc to get the value from the item.
EDIT: To enhance the visibility of my comment to this answer. I would advise against checking for NULL and storing Zero into your property because then when you save back you are changing a Null to a Zero even though nothing has been changed by the system. Now, reports etc may distinguish between NULL and Zero (very often) and could start doing strange things!
Null does NOT equal zero!! If you assume it does as a work around... What happens if I truly do want to record zero? How do you differentiate between a real zero and a "was null now zero" trick? Do it right, save yourself the pain!
Use nullable int, or just make your control for your int's too
reader["ShippingZip"] != DBNull.Value ? (int)reader["ShippingZip"] : default(int);
You should use a nullable int for your variable and cast it, like (int?). Int can only have a value; nullable types can also be null. When you use a nullable type, you can look at the property .HasValue. Here is the MSDN page: http://msdn.microsoft.com/en-us/library/2cf62fcy.aspx

Linq / XML - How do you handle non existing nodes?

I am trying to figure out how to handle nodes that do not exist for all of my "card" elements. I have the following linq query:
FinalDeck = (from deck in xmlDoc.Root.Element("Cards")
.Elements("Card")
select new CardDeck
{
Name = deck.Attribute("name").Value,
Image = deck.Element("Image").Attribute("path").Value,
Usage = (int)deck.Element("Usage"),
Type = deck.Element("Type").Value,
Strength = (int)deck.Element("Ability") ?? 0
}).ToList();
with the Strength item, I had read another posting that the ?? handles the null. I am getting the following error though:
Operator '??' cannot be applied to operands of type 'int' and 'int'
How do I handle this issue?
Thanks!
Rather than use the Value property, cast to string... and for the int, cast to int? instead. The user defined conversions to nullable types will return null if the source XAttribute/XElement is null:
FinalDeck = (from deck in xmlDoc.Root.Element("Cards")
.Elements("Card")
select new CardDeck
{
Name = (string) deck.Attribute("name"),
Image = (string) deck.Element("Image").Attribute("path"),
Usage = (int?) deck.Element("Usage"),
Type = (string) deck.Element("Type"),
Strength = (int?) deck.Element("Ability") ?? 0
}).ToList();
Note that this won't help for the case where the Image element is missing, as then it'll try to dereference a null element to find the path attribute. Let me know if you want a workaround for that, but it'll be a bit of a pain, relatively speaking.
EDIT: You can always create an extension method for this yourself:
public static XAttribute NullSafeAttribute(this XElement element, XName name)
{
return element == null ? null : element.Attribute(name);
}
Then call it like this:
Image = (string) deck.Element("Image").NullSafeAttribute("path"),

Categories

Resources