如何为可能为空的对象做ToString?


97

有没有一种简单的方法可以执行以下操作:

String s = myObj == null ? "" : myObj.ToString();

我知道我可以执行以下操作,但我确实将其视为黑客:

String s = "" + myObj;

如果Convert.ToString()为此具有适当的重载,那就太好了。


3
我没有发现第一个有什么问题。如果您认为第二种是hack,那么最好的选择就是编写一个执行空检查的实用程序函数。
尼克·拉尔森

PLZ你可以更准确的了解您的问题
FosterZ

3
string.Format(“ {0}”,myObj)接受空值。
Holstebroe 2010年

3
使用C#6.0,我们现在可以使用空条件运算符,例如theText?.ToString()或theText?.Trim()
Santosh

2
根据此答案,您 Convert.ToString()所做的第一件事恰恰是它。
drzaus

Answers:


175

C#6.0编辑:

使用C#6.0,我们现在可以使用简洁,免转换的原始方法版本:

string s = myObj?.ToString() ?? "";

甚至使用插值:

string s = $"{myObj}";

原始答案:

String s = (myObj ?? String.Empty).ToString();

要么

String s = (myObjc ?? "").ToString()

更简洁。

不幸的是,正如已经指出的那样,您通常需要在任一侧进行强制转换才能使此类型适用于非String或Object类型:

String s = (myObjc ?? (Object)"").ToString()
String s = ((Object)myObjc ?? "").ToString()

因此,尽管看起来很优雅,但演员表几乎总是必需的,在实践中并不是那么简洁。

如在其他地方建议的那样,我建议也许使用扩展方法来使它更干净:

public static string ToStringNullSafe(this object value)
{
    return (value ?? string.Empty).ToString();
}

会编译吗?合并运算符不检查类型吗?
尼克·拉森

1
它起作用,因为(object ?? string)返回对象,因为合并使用了最不常见的类型。但是我认为这不适用于接口,因为它不能决定选择哪个接口(因为每个类允许多个接口)。
codymanix

1
并不是我真正希望的解决方案,但我会接受的
codymanix 2010年

4
那个对象投下的票很丑陋,涉及拳击。
steinar 2011年

1
c#6的第一个选择非常优雅
Alexandre N.

40
string.Format("{0}", myObj);

string.Format将把null格式化为空字符串,并在非null对象上调用ToString()。据我了解,这就是您想要的。


3
我个人不喜欢这样。该代码可能比String s = myObj == null短得多。“”:myObj.ToString(),但是您完全隐藏了方法背后的原因。
AGuyCalledGerald 2014年

当然,这是微优化,但所需时间比仅仅多5倍"" + myObj。但我读过会创建额外的字符串。 str.Concat(myObj)似乎工作正常,并且“甚至更快”。
drzaus


13

使用扩展方法,您可以完成此操作:

public static class Extension
{
    public static string ToStringOrEmpty(this Object value)
    {
        return value == null ? "" : value.ToString();
    }
}

以下内容不会在屏幕上写入任何内容,也不会引发异常:

        string value = null;

        Console.WriteLine(value.ToStringOrEmpty());

扩展方法调用是否省略了对空值的常规检查...?
Matti Virkkunen 2010年

2
它补充说,您不必键入“ {0}”,并且可以选择描述您正在执行的方法的名称。当您执行多次时,此功能特别有用。您甚至可以将方法命名为ToStringOrEmptyWhenNull。
Pieter van Ginkel 2010年

2
如果OP认为这string s = "" + myObj;是骇人听闻的,则在空对象上调用函数应该属于同一条船。我会对此表示反对,但是它确实解决了手头的问题,我只是不同意用法。空对象应该抛出NullReferenceException,即使在扩展方法中也是如此。
尼克·拉尔森

2
@NickLarsen:我在大多数情况下都同意您的观点,但是有时候您只是想要简单方法调用的便利。方法名称应提示您可以使用null引用,例如的建议ToStringOrEmptyWhenNull
Jordão酒店

3
扩展方法在使用“ first”参数(this参数)时不会抛出异常,因为它们只是语法糖。也就是说x.SomeExtensionMethod()是语法糖SomeStaticClass.SomeExtensionMethod(x);因此,当xnull我们不试图调用一个方法null的对象,而是传递一个null对象的静态方法。当且仅当该方法检查null参数并在遇到这种情况时抛出时,扩展方法才会在null对象抛出时“调用” 。
杰森

7

我不同意这一点:

String s = myObj == null ? "" : myObj.ToString();

无论如何都是黑客。我认为这是清晰代码的一个很好的例子。显然,您想要实现什么,并且期望得到null。

更新:

我现在知道您不是在说这是黑客。但这是一个隐含的问题,您认为这种方式并非可行之路。在我看来,这绝对是最清晰的解决方案。


他没有说这种方法是黑客。实际上,除了暗示这并不简单之外,他没有说这是什么问题。我认为这种方法没有任何问题。+1,因为我会这样做。
Mark Byers 2010年

我同意OP ... c#中已经有一个空合并运算符-请参阅下面的文章。
安德鲁·汉隆

我认为在这种情况下,空合并运算符不太清楚,但是使用它也可以。
steinar

@Pieter公平。但是确实如此。问题是“是否有执行以下操作的简单方法:...”。确切的方法很简单!
steinar

我从未说过,这种方法是骇客。请重读我的问题。我只错过带有此功能的Framework中的一个小功能。
codymanix

4
string s = String.Concat(myObj);

我猜这将是最短的方法,而且性能开销也很微不足道。请记住,尽管对于代码阅读者来说,目的不是很清楚。


2
这是“” + myObj的显式形式,但更糟的是告诉这里发生了什么。反正很有趣。
codymanix 2010年

@codymanix我认为这Concat是不一样的- 实际上在下面进行了空检查并返回string.Emptyor arg0.ToString(),这似乎表现得更好(我的意思是,我们在这里说的是ms)。
drzaus

2

其实我不明白你想做什么。据我了解,您可以使用其他方式编写此代码。你在问这个吗?你能解释更多吗?

string s = string.Empty;
    if(!string.IsNullOrEmpty(myObj))
    {
    s = myObj.ToString();
    }

当然,我可以这样写,但是我想要一个简单的小函数调用,我想知道为什么.NET BCL中没有这样的内容
codymanix 2010年

当我们具有IsNullOrEmpty()方法时,您真的需要一个函数吗?
Serkan Hekimoglu 2010年

关于这一点,我一直希望合并运算符在您流畅的表达式中击中空引用时下一次失败,但是我完全理解为什么这是一个糟糕的主意。允许您执行此操作的替代也会很好。
尼克·拉森

1
string s = string.IsNullOrEmpty(myObj) ? string.Empty : myObj.ToString();
尼克·拉尔森

2

我的答案可能会被打败,但是无论如何,这仍然可行:

我会简单地写

字符串s =“” if(myObj!= null){x = myObj.toString(); }

使用三元运算符在性能方面是否有回报?我不知道我的头顶。

显然,正如上面提到的,您可以将此行为放入诸如safeString(myObj)之类的允许重用的方法中。


OMG如果object为null,那么可以调用ToString()吗?
codymanix 2010年

来吧,这是一个错字。我已将第一个=替换为!使其正确。但是您真的要给我-1打字错误吗?
jaydel

2

我有同样的问题,只需将对象转换为字符串即可解决。这也适用于null对象,因为字符串可以为null。除非您绝对不想使用null字符串,否则应该可以正常工作:

string myStr = (string)myObj; // string in a object disguise or a null

最短和最佳的解决方案。(Obj1 ??“”).ToString()实际上也首先将Obj1转换为字符串:)
TPAKTOPA

2

一些(速度)性能测试总结了各种选择,而不是#microoptimization(使用linqpad扩展名)确实很重要

选件

void Main()
{
    object objValue = null;
    test(objValue);
    string strValue = null;
    test(strValue);
}

// Define other methods and classes here
void test(string value) {
    new Perf<string> {
        { "coallesce", n => (value ?? string.Empty).ToString() },
        { "nullcheck", n => value == null ? string.Empty : value.ToString() },
        { "str.Format", n => string.Format("{0}", value) },
        { "str.Concat", n => string.Concat(value) },
        { "string +", n => "" + value },
        { "Convert", n => Convert.ToString(value) },
    }.Vs();
}

void test(object value) {
    new Perf<string> {
        { "coallesce", n => (value ?? string.Empty).ToString() },
        { "nullcheck", n => value == null ? string.Empty : value.ToString() },
        { "str.Format", n => string.Format("{0}", value) },
        { "str.Concat", n => string.Concat(value) },
        { "string +", n => "" + value },
        { "Convert", n => Convert.ToString(value) },
    }.Vs();
}

指出这一点可能很重要,Convert.ToString(...)它将保留一个空字符串。

结果

目的

  • nullcheck过去了1.00x 1221个滴答声(0.1221毫秒)[以1万次代表,每个1.221E-05毫秒]
  • 过去了1.14x 1387个滴答声(0.1387 ms)[以1万次代表,每个1.387E-05 ms]
  • 字符串+ 1.16x经过1415个滴答声(0.1415毫秒)[以1万次代表,每个1.415E-05毫秒]
  • str.Concat 1.16x经过1420个滴答声(0.142毫秒)[以1万次代表,每个1.42E-05毫秒]
  • 转换经过的1.58x 1931滴答声(0.1931毫秒)[以10K代表,每1.931E-05毫秒]
  • str.Format 5.45x 6655滴答过去了(0.6655 ms)[以10K代表,每6.655E-05 ms]

  • nullcheck过去了1.00x 1190个滴答声(0.119毫秒)[以1万次代表,每个1.19E-05毫秒]
  • 转换经过的1.01x 1200滴答声(0.12 ms)[以1万次代表,每个1.2E-05 ms]
  • 字符串+ 1.04x经过1239个滴答声(0.1239毫秒)[以1万次代表,每个1.239E-05毫秒]
  • 过去1.20x 1423滴答声(0.1423毫秒)[以10K代表,每个1.423E-05毫秒]
  • str.Concat经过4.57x 5444个滴答声(0.5444毫秒)[以10K代表,每个5.444E-05毫秒]
  • str.Format 5.67x经过6750个滴答声(0.675毫秒)[以1万次代表,每个6.75E-05毫秒]

1

Holstebroe的评论将是您最好的答案:

string s = string.Format("{0}", myObj);

如果myObj为null,格式将在此处放置一个空字符串值。

它还满足您的一条线要求,并且易于阅读。


是的,但是代码不清楚。您有多少开发人员会知道您要完成什么?
AGuyCalledGerald 2014年

0

即使这是一个古老的问题,并且OP要求使用C#,我还是想为那些使用VB.Net而不是C#的人共享一个VB.Net解决方案:

Dim myObj As Object = Nothing
Dim s As String = If(myObj, "").ToString()

myObj = 42
s = If(myObj, "").ToString()

不幸的是,VB.Net不允许在变量后使用?运算符,因此myObj?.ToString无效(至少在用于测试解决方案的.Net 4.5中无效)。相反,如果myObj ist Nothing,我使用If返回一个空字符串。因此,第一个Tostring-Call返回一个空字符串,而第二个(其中myObj不是Nothing)返回“ 42”。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.