Search code examples
c#nullablegeneric-programming

Generic method to return Nullable Type values


I wrote below method with follwing requirement -

  1. input is xmlnode and attributeName
  2. return the value if it is found with the associated attribute name passed
  3. 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.


Solution

  • 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...