2012-11-07 4 views
55

W poniższym kodzie poniżej, dlaczego dwa połączenia string.Format nie zachowują się w taki sam sposób? W pierwszym nie zostanie zgłoszony wyjątek, ale w drugim zostanie zgłoszony ArgumentNullException.W jaki sposób string.Format obsługuje wartości puste?

static void Main(string[] args) 
{ 
    Exception e = null; 
    string msgOne = string.Format("An exception occurred: {0}", e); 
    string msgTwo = string.Format("Another exception occurred: {0}", null); 
} 

Czy ktoś mógłby mi pomóc zrozumieć różnicę między tymi dwoma?

+7

Szanse są jesteś uderzanie [ 'nadpisanie params'] (http://msdn.microsoft.com/en-us/library/b1csw23d.aspx) w drugim przykładzie i' String.Format' testuje, że tablica jest wypełniana, zanim przejdzie do iteracji nad wartością kolekcji i wstawienia. –

+0

@BradChristie Powinieneś napisać to jako odpowiedź. – erikkallen

Odpowiedz

43

Zgaduję, ale wygląda na to, że różnica polega na tym, że masz przeładowane połączenie. String.Format ma wiele przeciążeń, tylko o to chodzi.

W pierwszym przykładzie sensownym jest, że uderzasz w String.Format(string,object).

W drugim przykładzie, dostarczając null jesteś najprawdopodobniej uderzenie String.Format(string,params object[]) które za dokumentację, by podnieść ArgumentNullException gdy: Format

lub args jest null.

Jeśli używasz .NET4, spróbuj za pomocą nazwanych parametrów:

String.Format("Another exception occured: {0}", arg0: null); 

Dlaczego jest to uderzanie przeciążenie params object[]? Prawdopodobnie dlatego, że null nie jest obiektem, a sposób, w jaki działa, polega na tym, że możesz przekazać albo każdą wartość jako nowy obiekt w wywołaniu lub przekazać tablicę wartości. To znaczy, są następujące one in the same:

String.Format("Hello, {0}! Today is {1}.", "World", "Sunny"); 
String.Format("Hello, {0}! Today is {1}.", new Object[]{ "World", "Sunny" }) 

Więc to przełożenie rozmowy oświadczenie coś wzdłuż linii:

String format = "Another exception occured: {0}"; 
Object[] args = null; 
String.Format(format, args); // throw new ArgumentNullException(); 
+0

Również: Wypróbuj różnicę między 'string.Format (" Occurred: {0} ", (object []) null)' i 'string.Format (" Occurred: {0} ", (object) null)'. Jest jeszcze jedna możliwość: 'string.Format (" Occurred: {0} ", new [] {(object) null,})'. Problem zdarza się tylko w pierwszym przypadku. –

8

w pierwszym przykładzie, jesteś uderzanie Format(String, Object), który wygląda jak to podczas demontażu:

public static string Format(string format, object arg0) 
{ 
    return Format(null, format, new object[] { arg0 }); 
} 

Zanotuj new object[] wokół tego.

Po drugie, najwyraźniej uderzasz w użycie Format(string, object[]), a przynajmniej to, które jest wywoływane, gdy wykonuję ten sam test. Zdemontowany, który wygląda tak:

public static string Format(string format, params object[] args) 
{ 
    return Format(null, format, args); 
} 

Więc wszystkie te rzeczywiście dostać funneled do Format(IFormatProvider, string, object[]). Fajnie, spójrzmy na pierwsze kilka linii:

public static string Format(IFormatProvider provider, string format, params object[] args) 
{ 
    if ((format == null) || (args == null)) 
    { 
     throw new ArgumentNullException((format == null) ? "format" : "args"); 
    } 
... 
} 

... welp, jest twój problem, właśnie tutaj! Pierwsze wywołanie jest zawijanie go w nowej tablicy, więc nie jest zerowy. Przekazywanie w wartości null jawnie tego nie powoduje, ze względu na konkretną instancję wywołującą Format().

2

Pierwsze połączenie zostanie rozstrzygnięte jako wywołanie funkcji Format (obiekt), a drugie zostanie rozpoznane jako wywołanie funkcji Format (obiekt []). Parametry zerowe są obsługiwane inaczej przez te różne przeciążenia.

Rozdzielczość przeciążenia jest opisana jako here. Odpowiednia część jest taka, że ​​dla drugiego wywołania Format, przeciążenie Format (obiekt params []) zostaje rozszerzone do Format (obiekt []), który jest preferowany do Format (obiekt). Dosłowna wartość zerowa jest zarówno obiektem [], jak i obiektem, ale obiekt [] jest bardziej szczegółowy, dlatego został wybrany.

-3

Są dwie różnice, które są następujące:

  1. Tutaj wartość Null jest przypisane.

    Exception e = null; 
    string msgOne = string.Format("An exception occurred: {0}", e); 
    
  2. Tutaj wartość Null nie mogą być odczytywane w formacie ciągu co oznacza typ odlewania błąd.

    string msgTwo = string.Format("Another exception occurred: {0}", null); 
    

dam ci prosty przykład: Tutaj nie można odczytać wartość NULL jako format strun.

string str = null.toString();