Reputation: 719
I wrote below method with follwing requirement -
Where there is no value in attributeName being passed, it should return -
3.1. For int -1 3.2. For Datetime DateTime.MinValue 3.3. For String, null 3.4. For bool, null
Below method fails for case 3.4.
public T AttributeValue<T>(XmlNode node, string attributeName)
{
var value = new object();
if (node.Attributes[attributeName] != null && !string.IsNullOrEmpty(node.Attributes[attributeName].Value))
{
value = node.Attributes[attributeName].Value;
}
else
{
if (typeof(T) == typeof(int))
value = -1;
else if (typeof(T) == typeof(DateTime))
value = DateTime.MinValue;
else if (typeof(T) == typeof(string))
value = null;
else if (typeof(T) == typeof(bool))
value = null;
}
return (T)Convert.ChangeType(value, typeof(T));
}
When change this to
public System.Nullable<T> AttributeValue<T>(XmlNode node, string attributeName) where T : struct
{
var value = new object();
if (node.Attributes[attributeName] != null && !string.IsNullOrEmpty(node.Attributes[attributeName].Value))
{
value = node.Attributes[attributeName].Value;
}
else
{
if (typeof(T) == typeof(int))
value = -1;
else if (typeof(T) == typeof(DateTime))
value = DateTime.MinValue;
else if (typeof(T) == typeof(string))
return null;
else if (typeof(T) == typeof(bool))
return null;
}
return (T?)Convert.ChangeType(value, typeof(T));
}
It fails for string type i.e. case 3.3
Looking forward for some help.
Upvotes: 12
Views: 10930
Reputation: 719
thanks for a number of replies, this is what I wrote and it works for me..
It returns null for the types.
public T AttributeValue<T>(XmlNode node, string attributeName)
{
object value = null;
if (node.Attributes[attributeName] != null && !string.IsNullOrEmpty(node.Attributes[attributeName].Value))
value = node.Attributes[attributeName].Value;
if (typeof(T) == typeof(bool?) && value != null)
value = (string.Compare(value.ToString(), "1", true) == 0).ToString();
var t = typeof(T);
t = Nullable.GetUnderlyingType(t) ?? t;
return (value == null) ?
default(T) : (T)Convert.ChangeType(value, t);
}
I call it like this
const string auditData = "<mydata><data><equipmentStatiticsData><userStatistics maxUsers='100' totalUsers='1' authUsers='0' pendingUsers='' adminAddedUsers='' xmlUsers='' internalDBUsers='' webUsers='' macUsers='' vpnUsers='' xUsers8021=''></userStatistics><equipmentStatistics cpuUseNow='14' cpuUse5Sec='1' cpuUse10Sec='1' cpuUse20Sec='1' ramTotal='31301632' ramUtilization ='1896448' ramBuffer='774144' ramCached='8269824' permStorageUse='24' tempStorageUse='24'></equipmentStatistics><authStatus status='1'></authStatus></equipmentStatiticsData></data></mydata>";
xmlDoc.LoadXml(auditData);
var userStatsNode = xmlDoc.SelectSingleNode("/mydata/data/equipmentStatiticsData/userStatistics");
var intNullable = AttributeValue<int?>(userStatsNode, "vpnUsers");
var nullableBoolTrue = AttributeValue<bool?>(userStatsNode, "totalUsers");
var nullableBoolFalse = AttributeValue<bool?>(userStatsNode, "authUsers");
var nullableString = AttributeValue<string>(userStatsNode, "authUsers");
var pendingUsersBoolNull = AttributeValue<bool?>(userStatsNode, "pendingUsers");
var testAttribNullableNotFoundDateTime = AttributeValue<DateTime?>(userStatsNode, "testAttrib");
var testAttrib1NullString = AttributeValue<string>(userStatsNode, "testAttrib");
var maxUsersNullInt = AttributeValue<int?>(userStatsNode, "maxUsers");
it works well for me. thanks people...
Upvotes: 6
Reputation: 23208
You need to call your first code set using bool?
not bool
because null
isn't a valid value for a non-nullable bool
.
Your second code block fails because you can't use string
for the generic type of Nullable<T>
as it requires a value-type struct
and string
is a reference-type class.
You'll need to change your first method block to look for typeof(bool?)
and call it with a nullable boolean type:
public T AttributeValue<T>(XmlNode node, string attributeName)
{
var value = new object();
if (node.Attributes[attributeName] != null && !string.IsNullOrEmpty(node.Attributes[attributeName].Value))
{
value = node.Attributes[attributeName].Value;
}
else
{
if (typeof(T) == typeof(int))
value = -1;
else if (typeof(T) == typeof(DateTime))
value = DateTime.MinValue;
else if (typeof(T) == typeof(string))
value = null;
else if (typeof(T) == typeof(bool?))
value = null;
}
var type = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T);
return (T)Convert.ChangeType(value, type);
}
Then call it as:
bool? value = AttributeValue<bool?>(node, "myAttributeName");
You also need to do a check as Convert.ChangeType
won't work for a nullable type. A quick fix from here resolves that. (it is included in the code above)
EDIT: Here's an improved/cleaned version of your method:
public T AttributeValue<T>(XmlNode node, string attributeName)
{
if (node.Attributes[attributeName] != null && !string.IsNullOrEmpty(node.Attributes[attributeName].Value))
{
var value = node.Attributes[attributeName].Value;
var type = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T);
return (T)Convert.ChangeType(value, type);
}
else
{
if (typeof(T) == typeof(int))
return (T)(object)(-1);
return default(T);
}
}
You can add additional special cases for non-existing nodes, but all your cases except for int
are already the default value for the types so just use default(T)
instead.
Upvotes: 0
Reputation: 34992
For 3.4 you need to use bool?
as the type for T, so you can return null.
Then you can use the default
keyword for 3.3 and 3.4 (string and bool?). As per msdn it will return null
for reference types and the default value for value types (like int or bool).
You can use it like
return default(T);
Upvotes: 7