Làm thế nào để thực hiện ToString cho một đối tượng có thể là null?


97

Có một cách đơn giản để làm như sau:

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

Tôi biết tôi có thể làm những điều sau, nhưng tôi thực sự coi đó như một vụ hack:

String s = "" + myObj;

Sẽ thật tuyệt nếu Convert.ToString () có quá tải thích hợp cho việc này.


3
Tôi không thấy có gì sai với cái đầu tiên. Nếu bạn coi cách thứ hai là một vụ hack, tốt nhất bạn nên viết một hàm tiện ích thực hiện kiểm tra null.
Nick Larsen 21/10/10

plz bạn có thể được chính xác hơn về câu hỏi của bạn
FosterZ

3
string.Format ("{0}", myObj) chấp nhận giá trị null.
Holstebroe 21/10/10

3
Với C # 6.0 bây giờ chúng ta có thể sử dụng các toán null-có điều kiện, như theText ToString () hoặc theText .Trim ()?
Santosh

2
Mỗi câu trả lời Convert.ToString() này thực hiện chính xác điều đầu tiên bạn đã viết bên dưới.
drzaus

Câu trả lời:


175

C # 6.0 Chỉnh sửa:

Với C # 6.0, bây giờ chúng ta có thể có một phiên bản ngắn gọn, không cần truyền của phương thức gốc:

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

Hoặc thậm chí sử dụng nội suy:

string s = $"{myObj}";

Câu trả lời gốc:

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

hoặc là

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

ngắn gọn hơn nữa.

Thật không may, như đã được chỉ ra, bạn thường cần ép kiểu ở cả hai bên để làm cho điều này hoạt động với các loại không phải Chuỗi hoặc Đối tượng:

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

Vì vậy, mặc dù nó có thể xuất hiện thanh lịch, nhưng việc diễn viên hầu như luôn luôn cần thiết và không hề ngắn gọn trong thực tế.

Như được đề xuất ở những nơi khác, tôi khuyên bạn có thể sử dụng một phương pháp mở rộng để làm cho điều này rõ ràng hơn:

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

Điều này sẽ biên dịch? Người điều hành liên hợp có kiểm tra các loại không?
Nick Larsen

1
Nó hoạt động vì (object ?? string) trả về đối tượng, vì liên kết sử dụng kiểu ít phổ biến nhất. Nhưng tôi nghĩ rằng điều này sẽ không hoạt động đối với các giao diện vì nó không thể quyết định giao diện nào được chọn (vì nhiều giao diện được phép cho mỗi lớp).
codymanix 21/10/10

1
Không thực sự là giải pháp tôi đã hy vọng cho nhưng tôi sẽ chấp nhận nó
codymanix

4
Từ chối khi vật thể đó được đúc là xấu kinh khủng và liên quan đến quyền anh.
steinar

1
tùy chọn đầu tiên để c # 6 là rất thanh lịch
Alexandre N.

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

string.Format sẽ định dạng null thành một chuỗi rỗng và gọi ToString () trên các đối tượng không phải null. Theo tôi hiểu, đây là những gì bạn đang tìm kiếm.


3
Cá nhân tôi không thích điều này. Mã có thể ngắn hơn không đáng kể so với Chuỗi s = myObj == null? "": myObj.ToString (), nhưng bạn hoàn toàn che giấu lý do đằng sau phương thức của mình.
AGuyCalledGerald

Được cho rằng đây là quá trình tối ưu hóa vi mô, nhưng nó mất nhiều thời gian hơn khoảng 5 lần "" + myObj. Nhưng tôi đã đọc điều đó tạo ra các chuỗi phụ. str.Concat(myObj)dường như hoạt động tốt và "thậm chí còn nhanh hơn".
drzaus

18

Sẽ thật tuyệt nếu Convert.ToString () có quá tải thích hợp cho việc này.

Đã có Convert.ToString(Object value)từ .Net 2.0 (khoảng 5 năm trước khi Q này được hỏi), dường như làm chính xác những gì bạn muốn:

http://msdn.microsoft.com/en-us/library/astxcyeh(v=vs.80).aspx

Tôi có thiếu / hiểu sai điều gì đó thực sự rõ ràng ở đây không?


1
Bạn không, họ làm. Tại sao đơn giản khi nó có thể phức tạp :)
alex.peter

13

Với một phương pháp mở rộng, bạn có thể thực hiện điều này:

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

Phần sau sẽ không ghi gì lên màn hình và sẽ không có ngoại lệ:

        string value = null;

        Console.WriteLine(value.ToStringOrEmpty());

Các cuộc gọi phương thức mở rộng có bỏ qua kiểm tra thông thường cho null không ...?
Matti Virkkunen 21/10/10

2
Nó cho biết thêm rằng bạn không phải nhập "{0}" và bạn có thể chọn tên phương thức mô tả những gì bạn đang làm. Điều này đặc biệt hữu ích khi bạn làm điều này nhiều lần. Bạn thậm chí có thể đặt tên cho phương thức là ToStringOrEmptyWhenNull.
Pieter van Ginkel 21/10/10

2
Nếu OP cho rằng đó string s = "" + myObj;là hackish, việc gọi một hàm trên một đối tượng null sẽ rơi vào cùng một chiếc thuyền. Tôi sẽ phản đối điều này, nhưng nó không giải quyết được vấn đề trong tầm tay, tôi chỉ không đồng ý với cách sử dụng. Các đối tượng rỗng nên ném NullReferenceException, ngay cả trong các phương thức mở rộng.
Nick Larsen

2
@NickLarsen: Tôi đồng ý với bạn trong hầu hết các trường hợp, nhưng đôi khi bạn chỉ muốn sự tiện lợi của một cuộc gọi phương thức đơn giản. Tên phương thức sẽ cung cấp cho bạn một gợi ý rằng các tham chiếu rỗng là OK, giống như với đề xuất cho ToStringOrEmptyWhenNull.
Jordão

3
Các phương thức mở rộng không ném khi tham số "đầu tiên" ( thistham số) vì chúng chỉ là đường cú pháp. Đó là x.SomeExtensionMethod()là cú pháp đường cho SomeStaticClass.SomeExtensionMethod(x);Vì vậy, khi xđược nullchúng ta không cố gắng để gọi một phương thức trên một nullđối tượng mà là đi qua một nullđối tượng đến một phương pháp tĩnh. Nếu và chỉ khi phương thức đó kiểm tra một nulltham số và ném khi gặp phải như vậy thì một phương thức mở rộng sẽ được "gọi" trên một nullném đối tượng.
jason

7

Tôi không đồng ý với điều này:

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

là một cuộc tấn công theo bất kỳ cách nào. Tôi nghĩ đó là một ví dụ điển hình về mã rõ ràng. Đó là điều hoàn toàn rõ ràng bạn muốn đạt được và bạn đang mong đợi vô hiệu.

CẬP NHẬT:

Tôi thấy bây giờ bạn đã không nói rằng đây là một cuộc tấn công. Nhưng nó ngụ ý trong câu hỏi rằng bạn nghĩ rằng cách này không phải là cách để đi. Trong tâm trí tôi, đó chắc chắn là giải pháp rõ ràng nhất.


Anh ấy không nói rằng phương pháp này là hack. Trên thực tế, anh ấy không nói điều gì sai với nó, ngoại trừ có lẽ ngụ ý rằng nó không đơn giản. Tôi không nghĩ rằng có bất cứ điều gì sai với phương pháp này. +1 vì tôi sẽ làm theo cách này.
Mark Byers

Tôi đồng ý với OP ... đã có một toán tử kết hợp null trong c # - hãy xem bài đăng của tôi bên dưới.
Andrew Hanlon 21/10/10

Tôi nghĩ toán tử liên kết null hơi kém rõ ràng hơn trong trường hợp này, tuy nhiên tôi sẽ ổn khi sử dụng điều đó.
steinar 21/10/10

@Pieter Đủ công bằng. Nhưng nó có. Câu hỏi là "Có một cách đơn giản để làm như sau: ...". Cách chính xác đó là đơn giản!
steinar 21/10/10

Tôi chưa bao giờ nói, mà này phương pháp là một hack. Vui lòng đọc lại câu hỏi của tôi. Tôi chỉ thiếu một chức năng nhỏ trong Framework có chức năng này.
codymanix 21/10/10

4
string s = String.Concat(myObj);

sẽ là con đường ngắn nhất mà tôi đoán và cũng có hiệu suất không đáng kể. Hãy ghi nhớ mặc dù nó sẽ không hoàn toàn rõ ràng cho người đọc mã mục đích là gì.


2
Đây là dạng rõ ràng của "" + myObj nhưng thậm chí còn tệ hơn khi kể những gì đang diễn ra ở đây. Thật thú vị.
codymanix 21/10/10

@codymanix Tôi không nghĩ nó giống nhau - Concatthực sự kiểm tra null bên dưới và trả về string.Emptyhoặc arg0.ToString(), có vẻ hiệu quả hơn một chút (ý tôi là, chúng ta đang nói chuyện ở đây).
drzaus

2

thực sự tôi không hiểu bạn muốn làm gì. Theo tôi hiểu, bạn có thể viết mã này theo cách khác như thế này. Bạn có đang hỏi điều này hay không? Bạn có thể giải thích thêm?

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

Chắc chắn tôi có thể viết nó như thế này nhưng tôi muốn có một đơn giản nhỏ chức năng gọi điện, tôi đã tự hỏi tại sao không có gì như thế này trong NET BCL là
codymanix

Bạn có thực sự cần một hàm trong khi chúng ta có phương thức IsNullOrEmpty () không?
Serkan Hekimoglu 21/10/10

Lưu ý rằng, tôi đã luôn muốn toán tử liên hợp thất bại tiếp theo khi nó chạm vào tham chiếu rỗng trong cách diễn đạt trôi chảy của bạn, nhưng tôi hoàn toàn hiểu tại sao đó là một ý tưởng khủng khiếp. Một ghi đè cho phép bạn làm điều đó cũng sẽ tốt.
Nick Larsen 21/10/10

1
string s = string.IsNullOrEmpty(myObj) ? string.Empty : myObj.ToString();
Nick Larsen

2

Tôi có thể bị đánh bại vì câu trả lời của mình nhưng dù sao thì đây cũng là:

Tôi chỉ đơn giản là viết

string s = "" if (myObj! = null) {x = myObj.toString (); }

Có phần thưởng nào về mặt hiệu suất khi sử dụng toán tử bậc ba không? Tôi không biết trên đỉnh đầu của mình.

Và rõ ràng, như ai đó ở trên đã đề cập, bạn có thể đặt hành vi này vào một phương thức như safeString (myObj) cho phép sử dụng lại.


OMG nếu đối tượng là null thì gọi ToString () trên nó?
codymanix 21/10/10

Nào, đó là lỗi đánh máy. Tôi đã thay thế = đầu tiên bằng! để làm cho nó chính xác. Nhưng bạn thực sự sẽ -1 tôi vì lỗi đánh máy?
jaydel

2

Tôi đã gặp vấn đề tương tự và đã giải quyết nó bằng cách đơn giản truyền đối tượng thành chuỗi. Điều này cũng hoạt động cho các đối tượng null vì các chuỗi có thể là null. Trừ khi bạn hoàn toàn không muốn có một chuỗi null, điều này sẽ hoạt động tốt:

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

Giải pháp ngắn nhất và tốt nhất. (Obj1 ?? "") ToString () thực sự đầu tiên phôi obj1 như chuỗi quá :)
TPAKTOPA

2

Một số bài kiểm tra hiệu suất (tốc độ) tóm tắt các tùy chọn khác nhau, không phải là nó thực sự quan trọng #microoptimization (sử dụng tiện ích mở rộng linqpad )

Tùy chọn

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

Có thể quan trọng là chỉ ra rằng Convert.ToString(...)sẽ giữ lại một chuỗi null.

Các kết quả

Vật

  • nullcheck 1,00x 1221 tích tắc trôi qua (0,1221 ms) [trong 10K đại diện, 1,221E-05 ms mỗi]
  • coallesce 1,14x 1387 tích tắc (0,1387 ms) [trong 10K đại diện, 1,387E-05 ms mỗi]
  • chuỗi + 1,16x 1415 tích tắc đã trôi qua (0,1415 ms) [trong 10K đại diện, 1,415E-05 ms mỗi]
  • str.Concat 1,16x 1420 tích tắc (0,142 mili giây) [trong 10K đại diện, 1,42E-05 mili giây mỗi]
  • Chuyển đổi 1,58x 1931 tích đã trôi qua (0,1931 ms) [trong 10K đại diện, 1,931E-05 ms mỗi]
  • str.Format 5,45x 6655 tích tắc trôi qua (0,6655 ms) [trong 10K đại diện, 6,655E-05 ms mỗi]

Chuỗi

  • nullcheck 1,00x 1190 lần tích tắc (0,119 ms) [trong 10K đại diện, 1,19E-05 ms mỗi]
  • Chuyển đổi 1,01x 1200 tích tắc trôi qua (0,12 mili giây) [trong 10K đại diện, 1,2E-05 mili giây mỗi]
  • chuỗi + 1,04x 1239 tích tắc trôi qua (0,1239 ms) [trong 10K đại diện, 1,239E-05 ms mỗi]
  • coallesce 1,20x 1423 tích tắc (0,1423 ms) [trong 10K đại diện, 1,423E-05 ms mỗi]
  • str.Concat 4,57x 5444 tích tắc trôi qua (0,5444 mili giây) [trong 10K đại diện, 5,444E-05 mili giây mỗi]
  • str.Format 5,67x 6750 tích tắc trôi qua (0,675 ms) [trong 10K reps, 6,75E-05 ms mỗi]

1

Nhận xét của Holstebroe sẽ là câu trả lời tốt nhất cho bạn:

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

Nếu myObjlà null, Định dạng sẽ đặt một giá trị Chuỗi trống ở đó.

Nó cũng đáp ứng yêu cầu một dòng của bạn và dễ đọc.


có, nhưng mã không rõ ràng. Có bao nhiêu nhà phát triển đồng nghiệp của bạn sẽ biết bạn đang cố gắng hoàn thành điều gì?
AGuyCalledGerald

0

Mặc dù đây là một câu hỏi cũ và OP yêu cầu C #, tôi muốn chia sẻ một giải pháp VB.Net cho những người làm việc với VB.Net thay vì C #:

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

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

Rất tiếc, VB.Net không cho phép? -Operator sau một biến nên myObj? .OString không hợp lệ (ít nhất là không có trong .Net 4.5, cái mà tôi đã sử dụng để thử nghiệm giải pháp). Thay vào đó, tôi sử dụng If để trả về một chuỗi trống trong trường hợp myObj ist Không có gì. Vì vậy, Tostring-Call đầu tiên trả về một chuỗi trống, trong khi chuỗi thứ hai (trong đó myObj không phải là Không có gì) trả về "42".

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.