在进行强制类型转换和赋值之前,先检查值是否为null。

4

我正在使用 c# .net 2.0,需要检查分配给我的对象的方法返回的值是否为空。

我的代码如下:

MyObjectValue myObjectValue= (MyObjectValue) myObjectField.GetFieldValue();

在这种情况下,myObjectField.GetFieldValue()返回的值可能为空,因此我想在分配给myObjectValue之前进行检查。目前它会抛出异常“对象引用未设置为对象的值”。
实际的代码行正在使用SharePoint API。
SPFieldUserValue lawyerResponsibleFieldValue = 
    (SPFieldUserValue)lawyerResponsibleUserField.GetFieldValue(
              workflowProperties.Item[lawyerResponsibleUserField.Id].ToString());

显然,赋值语句不能抛出异常,所以你的问题是 myObjectField 为空,而不是返回值或者 GetFieldValue 方法内部的某些东西。 - John Leidegren
@John:或者转换失败,如果MyObjectValue是值类型的话。 - Adam Robinson
4
实际的代码和原来的几乎完全不同。你引入了许多可能导致 NullReferenceException 的原因。请查看我的编辑。 - Jon Skeet
2
天啊,那是一行非常复杂的代码。你需要分解它;测试每个值是否为null,以确定问题所在。 - Michael Petrotta
可能导致空引用异常的列表:https://dev59.com/O2445IYBdhLWcg3w3N6z#4660186 - Justin
9个回答

6
如果myObjectField本身不为空,则上述代码不会抛出NullReferenceException,除非MyObjectValue是值类型。您确定问题不是在使用myObjectValue时没有检查它是否为空?但是,假设GetFieldValue返回object,最简单的方法就是使用一个临时变量:
object tmp = myObjectField.GetFieldValue();
if (tmp != null)
{
    MyObjectValue myObjectValue = (MyObjectValue) tmp;
    // Use myObjectValue here
}

显然,无论MyObjectValue是引用类型还是值类型,这都可以正常工作。

编辑:现在你已经发布了完整的代码行,它可能会在许多地方引发NullReferenceException异常。我强烈建议您将该一行代码拆分为几个行以找出问题所在。


@nav: "MyObjectValue" 是值类型还是引用类型? - Jon Skeet
从他的编辑中可以看出,MyObjectValue 实际上是一个引用类型 SPFieldUserValue - Justin
@Justin:是的,编辑完全改变了问题 :) - Jon Skeet

5
C# 6(Visual Studio 2015)引入了空值条件(又称Elvis运算符)...
而不是这样...
myObjectValue = (myObjectValue == null) ? null : myObjectValue.child;

以下内容可用...
myObjectValue = myObjectValue?.child;

4

任何情况下,使用.访问成员时,如果左侧是引用类型(类),它可能为空。

此代码片段有多个可能出现空值的位置:

workflowProperties.Item[lawyerResponsibleUserField.Id].ToString()
                  ^                               ^   ^

首先,我会进入调试会话并检查现有的值,并阅读与该问题相关的任何文档。然后,我可能会重新考虑编写这段代码的方式。

if (lawyerResponsibleUserField != null
    && lawyerResponsibleUserField.Id != null)
{
    return Convert.ToString(workflowProperties != null 
            ? workflowProperties.Item[lawyerResponsibleUserField.Id] 
            : null
    )
}

假设这些属性是引用类型,可能是空值。
有很多方法可以检查空值并短路求值。一个好的提示是避免使用实例方法.ToString(),而是使用静态方法Convert.ToString(),它不会在传递的值为空时抛出异常。返回值仍然可能是空值,但至少您不必太担心提供的参数。

1

如果你想要真正的安全:

MyObjectValue myObjectValue = null;

if(myObjectField != null)
{
    object temp = myObjectField.GetFieldValue();
    if(temp != null)
    {
        myObjectValue = (MyObjectValue)temp;
    }
}

(cast)null 是可以的,结果为 null -- 我经常会“利用”这个特性。有时候也会用来提供方法的类型信息,以及类型推断等。在这里只有外部条件是有用的。例如:T Coerce<T>(object val, T defaultValue) { ... }; string s = Coerce(fuuba, (string)null); - user166390
以前的评论没有涉及到 ValueTypes。留作历史记录,但是“非常安全”的应用并不需要知道 MyObjectValue 的类型。 - user166390

1

我有一种感觉,实际上是myObjectField为空,而不是myObjectField.GetFieldValue()。如果是这样的话,那么一个简单的空值检查就可以正常工作:

 MyObjectValue myObjectValue;
if  (myObjectField == null)
{
    // recover
}
else 
{
    myObjectValue = (MyObjectValue) myObjectField.GetFieldValue();
}

几行调试代码就能为您验证:
Console.WriteLine("myObjectField=" + myObjectField);

如果你在那里看到了 null,那么就是 myObjectField 是 null。

1

你可能在其他地方出现了错误;如果MyObjectValue是一个引用类型(一个class,而不是一个struct),那么将null转换为你的类型时不应该有异常。如果MyObjectValue是一个值类型(一个struct,而不是一个class),那么你不能将null值赋给它。

你可以使用合并运算符来处理null的情况。

MyObjectValue value = (MyObjectValue)(field.GetFieldValue() ?? (object)someValidValue);

someValidValue 表示在 GetFieldValue 返回 null 的情况下,您想要用作默认值的值。这会稍微有些昂贵,因为必须将 someValidValue 强制转换为对象进行装箱,但这应该可以满足您的需求。


不会更好。(cast)null没问题。问题是field可能为空。除非我正在遭受问题编辑错误。最好是((MyObjectValue)field.GetFieldValue()) ?? someMyObjectValue,以避免空引用异常。 - user166390
我的错。+1,因为这确实解决了MyObjectValue是ValueType的情况。其他评论仅作历史记录。 - user166390

1

以下建议仅为null值的示例

如果对象为null,则object.ToString()会引发错误。

在下面的代码中,我使用ComboBox作为示例。

因此,最好的方法是检查

// 1)
if (cmb.SelectedValue == null)
{
   // do something
}

并且如果你想使用内联

// 2)
string strValue = (cmb.SelectedValue ?? "-1").ToString();
// or
string strValue = cmb.SelectedValue == null ? "-1" : cmb.SelectedValue.ToString();

最后一种方法是处理错误。

// 3)
string strValue = "";
try
{
   strValue = cmb.SelectedValue.ToString();
}
catch
{
  strValue = "-1";
}

0

这应该可以工作。

if (myObjectField  != System.DBNull.Value))
{
    string variable = myObjectField.ToString();
}

0
 public IQueryable GetOrderDetails()
    { 
        var _db = new ProductContext();
        IQueryable<OrderDetail> query = _db.OrderDetails;

        if (ddlOrder.SelectedValue != null && ddlOrder.SelectedItem != null)
        {
            var id = Convert.ToInt32(ddlOrder.SelectedValue);

            query = query.Where(p => p.Username == User.Identity.Name && p.OrderId == id);
                }   
       else{ query = null; ddlOrder.Visible = false;btnSubmit.Visible = false; }
        return query;
           }

对于@Van(和未来的用户)来说,听到您解释为什么这是正确答案会很有帮助。 - Josh Gust
如果下拉框的值为空或者没有选择项或者下拉列表中没有数据,则我们可以使用它。if (ddlOrder.SelectedValue != null && ddlOrder.SelectedItem != null) - Automata company

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