web-dev-qa-db-fra.com

Comment string.Format gère les valeurs nulles?

Dans le code suivant ci-dessous, pourquoi les deux string.Format les appels ne se comportent pas de la même manière? Dans le premier, aucune exception n'est levée, mais dans le second un ArgumentNullException est levé.

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

Quelqu'un pourrait-il m'aider à comprendre la différence entre les deux?

61
Martin

Je suppose ici, mais cela semble être la différence de l'appel surchargé que vous frappez. String.Format a plusieurs surcharges, c'est à peu près ce que vous frappez.

Dans le premier exemple, il serait logique que vous frappiez String.Format(string,object) .

Dans le deuxième exemple, en fournissant null, vous frappez très probablement String.Format(string,params object[]) qui, selon la documentation, lèverait un ArgumentNullException lorsque:

format ou args est null.

Si vous exécutez .NET4, essayez d'utiliser des paramètres nommés:

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

Pourquoi atteint-il la surcharge params object[]? Probablement parce que null n'est pas un objet, et la façon dont params fonctionne est que vous pouvez passer soit chaque valeur en tant que nouvel objet dans l'appel ou passez-lui un tableau de valeurs. Autrement dit, les éléments suivants sont n dans le même :

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

Il s'agit donc de traduire l'appel de votre déclaration en quelque chose comme:

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

Dans votre premier exemple, vous frappez Format(String, Object), qui ressemble à ceci une fois démonté:

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

Notez le new object[] Autour de cela.

Le second, vous êtes apparemment en train d'utiliser Format(string, object[]), du moins c'est celui qui est invoqué lorsque j'effectue le même test. Démonté, cela ressemble à ceci:

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

Tous ces éléments sont donc acheminés vers Format(IFormatProvider, string, object[]). Cool, regardons les premières lignes là-bas:

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

... welp, il y a votre problème, là! La première invocation l'enveloppe dans un nouveau tableau, il n'est donc pas nul. Passer explicitement null ne le fait pas faire cela, en raison de l'instance spécifique de Format() qui appelle.

11
tmesser

Si vous utilisez une chaîne interpolée ($ "", une autre façon de formater), le null est ignoré, ignoré. Alors

string nullString = null;
Console.WriteLine($"This is a '{nullString}' in a string");

produira: "Ceci est un '' dans une chaîne". Bien sûr, vous pouvez utiliser l'opérateur de coalescence nul en cas de null pour produire la sortie requise:

string nullString = null;
Console.WriteLine($"This is a '{nullString ?? "nothing"}' in a string");
2
Gerard

Le premier appel est résolu comme un appel à Format (objet), tandis que le second est résolu comme un appel à Format (objet []). Les paramètres nuls sont traités différemment par ces différentes surcharges.

La résolution de surcharge est décrite ici . La partie pertinente est que pour le deuxième appel à Format, une surcharge de Format (objet params []) est étendue à Format (objet []), qui est préférée à Format (objet). Le null littéral est à la fois un objet [] et un objet, mais l'objet [] est plus spécifique, donc c'est choisi.

2
RossFabricant