返回可空类型值的通用方法

12
我根据以下要求编写了下面的方法:
  1. 输入为xmlnode和attributeName
  2. 如果找到与传递的属性名称相关联的值,则返回该值
  3. 当传入的attributeName没有对应值时,应返回:

    3.1. 对于int类型,返回-1 3.2. 对于DateTime类型,返回DateTime.MinValue 3.3. 对于String类型,返回null 3.4. 对于bool类型,返回null

下面的方法无法处理第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));
        }

将此更改为

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

它无法处理字符串类型,即情况3.3

期待得到一些帮助。


在你的第一组代码中,如何“调用”该方法?你需要将其称为 AttributeValue<bool?>(...)。如果你只是调用 AttributeValue<bool>(...),那么 null 不是 bool 的有效值。编辑:你的第二个案例失败了,因为 string 不能用于 System.Nullable<T>,因为 string 不是值类型结构体。 - Chris Sinclair
3个回答

7

对于3.4版本,您需要使用bool?作为T的类型,这样您就可以返回null。

然后您可以在3.3和3.4中使用default关键字(string和bool?)。

根据msdn,它将返回引用类型的null和值类型的默认值(如int或bool)。

您可以像下面这样使用它

return default(T);

1
对于 bool 情况(3.4),要求返回 null。然而,它实际上会返回 false,这与未找到匹配属性的情况以及提供了字符串 "false" 的情况无法区分。 - Chris Sinclair
你不觉得需要使用带有 bool? 作为泛型参数的方法吗?在该情况下返回 null。我的意思是,如果 T 是 bool,则无法返回 false,因此需要使用 bool?... - Daniel J.G.
只是为了澄清,对于 bool? 类型,default(T) 将返回 null。 - Daniel J.G.
当然,也许在你的答案中只是明确说明一下。我原来认为它会用于bool,而不是bool?。你完全正确。 - Chris Sinclair

6
感谢多位用户的回复,以下是我的写法并且它可以正常工作。
对于类型返回null。
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);
        }

我会把它称为这样。
    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");

对我来说,它运行良好。感谢大家...


我现在可以接受返回空值。这看起来是一个更好的解决方案。 - CuriousBenjamin

0

你需要使用bool?而不是bool来调用你的第一个代码集,因为null不是非空bool的有效值。

你的第二个代码块失败了,因为你不能使用string作为Nullable<T>的泛型类型,因为它需要一个值类型struct,而string是一个引用类型类。

你需要更改你的第一个方法块,查找typeof(bool?)并使用可空布尔类型进行调用:

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

然后调用它:

bool? value = AttributeValue<bool?>(node, "myAttributeName");

您还需要进行检查,因为Convert.ChangeType无法处理可空类型。从这里获取的快速修复可以解决此问题。(已包含在上面的代码中)

编辑:这是您方法的改进/清理版本:

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

你可以为不存在的节点添加额外的特殊情况,但除了int之外,所有的情况都已经是类型的默认值了,所以只需使用default(T)即可。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接