Im using linq to xml to write out a little config file for an application and was a little surprised to discover XAttributes dont accept null as their value - they throw an exception instead.
Null is a perfectly valid value for many of the properties in my config and I dont want to have to null check attributes everywhere:
var attribute = _element.Attribute(attribute);
var value = attribute == null ? null : attribute.Value;
A further reason I dont want to write code like this is that it will make it easier to mis type names of things - eg if an attribute is spelled wrong it will just act like an attribute that exists but has a null value rather than throwing an exception.
The solution I have at the moment is as follows but it seems a little bit ugly + like something you shouldnt need to do.
I've knocked up a little class to make it a bit easier to write + read xml and am using a string containing just the null character to signal a null string.
I've omitted everything except the indexer for brevity:
public class XContainerWrapper
{
private readonly XElement _element;
public XContainerWrapper(XElement xElement)
{
_element = xElement;
}
public string this[string attribute]
{
get
{
var value = _element.Attribute(attribute).Value;
return value == "\0" ? null : value;
}
set
{
var valueToWrite = value ?? "\0";
_element.Add(new XAttribute(attribute, valueToWrite));
}
}
}
You can write your own extension method instead of XAttribute Value getter:
public static class XmlExtensions {
public static string SafeValue(this XAttribute attribute) {
var value = attribute == null ? null : attribute.Value;
return value;
}
}
Then you can use
XAttribute a = null;
var value = a.SafeValue();
Related
Let's say I have a model class that looks like this:
public class ModelTest {
public string val1 {get;set;}
public string val2 {get;set;}
public string val3 {get;set;}
}
Somewhere in my code this ModelTest gets its data. The caveat is that, only 1 of them will hold a value
var model = new ModelTest() {val1=null, val2="value", val3=null} //Sudo code
What I am trying to do somehow, is compare a value to whichever 1 of the 3 items can potentially have a values, so something like:
var testCompare = "someValue"
if (testCompare == model. ....//how can I get the NOT NULL value from ModelTest here for comparison
While your data model isn't ideal, it is possible to check each of the properties by utilizing the || operator to compare each value. As long as your testCompare variable does not contain null, you can also omit a null check.
if (model.val1 == testCompare ||
model.val2 == testCompare ||
model.val3 == testCompare)
{ }
As mentioned in the comments, if you want a more succinct version, you can use the null coalescing operator, ??, to check subsequent properties if your prior property returns null. At the end of the null coalescing chain, the first non-null property will be compared to your testCompare string. Note that you must wrap all three properties in parentheses and that this has different behavior; it only tests the first non-null property whereas the previous version tests ALL properties for a match.
if (testCompare == (model.val1 ?? model.val2 ?? model.val3))
{
}
You could add a property to your ModelTest class that provides the first non-null value (if any) in your object:
public class ModelTest
{
public string val1 { get; set; }
public string val2 { get; set; }
public string val3 { get; set; }
public string val => val1 ?? val2 ?? val3;
}
and then check against that:
if (model.val == testCompare) { }
You could probably create a method (or even property) like:
public string Val()
{
if (val1 != null) return val1;
if (val2 != null) return val2;
if (val3 != null) return val3;
return null;
}
There is probably a shorter way to write this code. Also, if two or more of the values are not null, then it will return the first one.
It's a very bizarre use case, but let's go with it. Here's another option for the bonfire..
public class ModelTest {
private string _val;
public string val1 {get => _val; set => _val ??= value;}
public string val2 {get => _val; set => _val ??= value;}
public string val3 {get => _val; set => _val ??= value;}
}
Whichever one of these is set to non null ends up committing that value to _val - ??= writes the right hand into the left hand only if the left hand is null, essentially like left = left ?? right.
It doesn't matter which you use to access the value..
Note that there is only one data storage location so this approach is incapable of remembering two values, or which value was the non null. You wouldn't use this for disparate properties like name, address and social security number because it could lead to bizarre effects elsewhere. This is for a very narrow use case of "there are three properties that are essentially the same thing, they cannot be collapsed to one, and I don't know which one will be set but i can treat them equivalent for reading"
You can override the method 'Equals' of ModelTest class however you like. Example:
public class ModelTest {
public string val1 {get;set;}
public string val2 {get;set;}
public string val3 {get;set;}
public override bool Equals(object obj)
{
if(!typeof(string).IsInstanceOfType(obj))
return base.Equals(obj);
string value = obj as string;
if (val1.Equals(value))
return true;
if (val2.Equals(value))
return true;
if (val3.Equals(value))
return true;
return false;
}
}
For to use the method:
if(model.Equals("yourValue"))
...
What about solution which contains combination of reflection and Linq,
Test Data
var model = new ModelTest() {val1=null, val2="value", val3=null} ;
Usage
var result =
model.GetType()
.GetProperties()
.FirstOrDefault(prop => prop.GetValue(model, null) != null);
Print result
Console.WriteLine(result.GetValue(model));
This is my first attempt with reflection, suggestions are most welcome
.Net fiddle
Note: This is just an alternate solution, less performant. If you are looking for elegant solution, then kindly try other solutions.
I'm getting these warnings from CodeContracts:
Array access might be above the upper bound. Did you meant 0 instead of 1?
Array access might be above the upper bound. Did you meant 1 instead of 2?
Array access might be above the upper bound. Did you meant 2 instead of 3?
Array access might be above the upper bound. Did you meant 3 instead of 4?
On this line of code:
private readonly string[] _addr;
public string AddressLine1
{
get
{
return _addr[0] ?? _addr[1] ?? _addr[2] ?? _addr[3];
}
}
public string AddressLine2
{
get
{
return _addr[1] ?? _addr[2] ?? _addr[3];
}
}
public string AddressLine3
{
get
{
return _addr[2] ?? _addr[3];
}
}
How do I tell the Contracts analyzer that these indices are guaranteed inside bounds? _addr is initialized in the constructor to string[4].
I was able to get rid of these warnings by adding a method to that class that defined the invariants:
[ContractInvariantMethod]
private void AddressInvariants()
{
Contract.Invariant(_addr.Length == 4);
}
However, I think there's also a bug in your code.
If _addr[0] == null and _addr[1] != null, then AddressLine1 and AddressLine2 return the same value. This seems like a bug.
You can fix this easily enough (and remove the need to specify contract invariants) by using something along the lines of what #ryanyuyu mentioned:
public string AddressLine1
{
get
{
// Use the first non-null element.
return _addr.Where(x => x != null).FirstOrDefault();
}
}
public string AddressLine2
{
get
{
// Use the second non-null element.
return _addr.Where(x => x != null).Skip(1).FirstOrDefault();
}
}
public string AddressLine3
{
get
{
// Use the third non-null element.
return _addr.Where(x => x != null).Skip(2).FirstOrDefault();
}
}
ContractInvariantMethod works when _addr is a class member. But Contract.Assert() works with local variables too.
static void MyParse(string foo)
{
string[] split = foo.Split(',');
Contract.Assert(split.Length == 4);
string a = split[0];
string b = split[1];
string c = split[2];
string d = split[3];
}
I don't know about the Contracts analyzer, but your code could be cleaner. You are basically repeating code that just finds the first non-null string (and if the last element is null, you are returning that regardless). I'm a fan of using LINQ .FirstOrDefault which will let you find the first element that matches a condition (in your case not null). If no such element is found, it returns the default value (for a String it's null)
return _addr.FirstOrDefault(str => str != null);
See it in action at this .NET Fiddle.
I am deserializing an XML configuration file by performing the following:
XmlSerializer deserializer = new XmlSerializer(typeof(MyType));
using (TextReader textReader = new StreamReader(fn))
{
return (MyType)deserializer.Deserialize(textReader);
}
Then I have a simple method to check if the XML configuration file matches the values in the current UI.
if ((config.Description == null || config.Description != this.Description.Text)
|| (config.Location == null || config.Location != this.Location.Text)
|| (config.Provider == null || config.Provider != this.Provider.Text))
So if I have an older configuration file containing just config.Description, then config.Location and config.Provider will be null when the XML file is deserialized. How can I just simplify this so that config.Location is set to the default value for the typed property instead (in this case the strings would be set to zero-length strings), allowing me to drop all the null checks? For example:
if (config.Description != this.Description.Text
|| config.Location != this.Location.Text
|| config.Provider != this.Provider.Text)
I know one option is to create an instance besides the deserialized instance and loop through all properties using Reflection (or some other similar approach) but I was hoping there was a built-in way to assign default values to properties that weren't deserialized. I'm mostly wondering if this is the correct approach, as I'm trying to reduce unnecessary bloat when dealing with a larger amount of settings.
I've searched for duplicates of this problem, but most people are trying to deserialize an instance into itself and using the serialization event to control that behavior.
The XmlSerializer requires a parameterless constructor. However you can use any of the initialization techniques as shown below:
public class MyType
{
private string _description = default(string); // Note the default is NULL, not "" for a string
// However, why not determine the default yourself?
private string _location = "";
private string _provider;
public MyType()
{
// Or use the constructor to set the defaults
_provider = string.Empty;
}
public string Description
{
get { return _description; }
set { _description = value; }
}
}
"..I was hoping there was a built-in way to assign default values to properties that weren't deserialized.."
You can set default values in the class constructor.
I am able to assign a variable like below:
if (Session["myVariable"] != null)
{
string variAble = Session["myVariable"].ToString();
}
Is there a method which checks whether an object is null or not and then assign if it is not null?
string variAble = Session["myVariable"] ?? "";
EDIT A slightly more robust form, as suggested by #hatchet, is:
string variAble = (Session["myVariable"] ?? "").ToString();
While this isn't anything new, you can use the conditional operator to potentially simplify this:
string variable = Session["myVariable"] != null ? Session["myVariable"].ToString() : "Fallback";
You could write an extension method, as those still work with null objects.
public static class StringExtensions
{
public static String ToNullString(this object o)
{
return o == null ? "" : o.ToString();
}
}
I would consider it poor form though - it'll be confusing to whoever will be supporting the code after you, or even to you a few months down the track. It's probably better to just do the null check.
I have an object like this:
class MyObject
{
public string Object.Prop1 { get; set; }
public string Object.Prop2 { get; set; }
}
I'm writing a custom JSON converter and I'm serializing this object like this:
Dictionary<string, object> OutputJson = new Dictionary<string, object>();
OutputJson.Add("TheProp1", MyObject.Prop1.Trim());
If for some reason Prop1 is null, will the code encode TheProp1 as "" or will it crash?
If Prop1 is null your code will throw a NullReferenceException. You need to test if Prop1 is null before calling Trim:
MyObject.Prop1 == null ? "" : MyObject.Prop1.Trim()
Or you can do it more concisely with the null-coalescing operator:
(MyObject.Prop1 ?? "").Trim()
Another way to handle this is to use private member to handle the property values of properties where you need a default value rather than null
Class MyObject
{
private string _prop1 = String.Empty;
public string Object.Prop1 {
get
{
return _prop1;
}
set
{
_prop1 = value;
}
}
}
It will crash with a NullReferenceException, since you can't call Trim on null. You could do this instead:
OutputJson.Add("TheProp1", MyObject.Prop1 == null ?
string.Empty :
MyObject.Prop1.Trim());
My understanding is that a null is not an empty string. If you want to insure that this is going to work simply wrap the Value of the add in an if and insert your empty string as the null place holder. Of course you'll need to take the appropriate action when you decode your json.
If you don't need polymorphic behaviour for MyObject you can declare it as a struct instead of a class. It will have value semantic and every value will be initialize using its default. I am assuming inside your class you have just struct type (eg. int, string, double).
you can use DBNull class in filling the object
UserName = DBNull.Value != reader["UserName"] ? reader["UserName"].ToString() : default(string);