Why string.Format does not throw ArgumentNullException? - c#

According to MSDN String.Format throws if format is null (pretty reasonable), link here.
But testing says it only does that if the second argument is null as well, not if the second one is populated.
The following does not throw:
string test = string.Format(null, "string");
The following throws complaining about the first parameter (format):
string test = string.Format(null, null);
Digging futher with JustDecompile the source code calls the following method:
private static string FormatHelper(IFormatProvider provider, string format, ParamsArray args)
{
if (format == null)
{
throw new ArgumentNullException("format");
}
return StringBuilderCache.GetStringAndRelease(StringBuilderCache.Acquire(format.Length + args.Length * 8).AppendFormatHelper(provider, format, args));
}
Which makes no sense as format is null and no exception is thrown. Any hints?

Ah, the joys of overload resolution. In that case, you're actually calling string.Format(IFormatProvider, string, params object[]) - so you're passing a null argument for the provider parameter, which is entirely valid (and means to use the current culture).
That overload is "better" because the conversion of the second argument from string literal to string is better than the conversion from string literal to object.
If you use argument names to force the right overload, load this:
string text = string.Format(format: null, arg0: "string");
... then it throws an exception as expected.

Related

How to avoid input string/StringBuilder in an incorrect format error in C#

I'm using a string builder to append text to string.
StringBuilder content = new StringBuilder(GetStartHTML("installation",string.Empty));
.......
content.AppendFormat("<td>" + idcStepEntity.Comment + "</td>");
Unfortunetly i cannot control what comes in from the customer as comment, so i they write something like : comment { commment] comment (and they often do) i get string was not in a correct format error.
That mean i should not use a StringBuilder here? Should i usestring += otherstring or is there any other String class that can bu usefull here?
Thanks in advance :)
Having an unescaped "{" or "}" in the 1st argument of String.Format() will cause this exception.
This will cause the exception to be raised:
Microsoft.VisualBasic.MsgBox(String.Format("{"))
This is OK:
Microsoft.VisualBasic.MsgBox(String.Format("{0}", "{"))
Solution:
To escape "{" use "{{" and to escape "}" use "}}. Depending on your implementation, this could work for you.
Dim s As String = "{Hello}"
s = s.Replace("{", "{{")
s = s.Replace("}", "}}")
Stack trace:
It may appear in the stack trace to be a StringBuilder error because String.Format internally implements System.Text.StringBuilder, but you will get this exception even if you never use a StringBuilder in your project.
System.FormatException: Input string was not in a correct format.
at System.Text.StringBuilder.AppendFormatHelper(IFormatProvider provider, String format, ParamsArray args)
This error is possible only with StringBuilder.AppendFormat and if your string contains { or }. So the solution is to use StringBuilder.Append (as you don`t really use the format part):
content.Append("<td>" + idcStepEntity.Comment + "</td>");
Try this:
content.AppendFormat("<td>{0}</td>", idcStepEntity.Comment);
Note that, your exception is because your idcStepEntity.Comment may contain some block {}, then when you pass it into AppendFormat, the following overload will be used:
AppendFormat(string format, params object[] args);
That means it considers your idcStepEntity.Comment as the format string and there is not any arguments, that format string contains some invalid block {} and hence the exception is thrown.

Formatting string dates with String.Format()

Just curious...
So I get that if I convert the string version of the date to a DateTime object and pass it into the String.Format() method, then I"ll get the desired results.
String.Format("The date is {0:MMMM dd, yyyy}", DateTime.Parse("05-22-2012"));
"The date is May 22, 2012"
But why doesn't this work?
String.Format("The date is {0:MMMM dd, yyyy}", "05-22-2012")
"The date is 05-22-2012"
Sorry if this is a stupid question, but I'm just trying to understand how this works.
Thanks
The other answers here hit on salient points, but let's put them all together an examine how String.Format works.
It has five overloads, but we're going to talk only about the one that they all redirect to (this is not the actual code, if you want to see it with Reflector or ILSpy, you will find it in StringBuilder.AppendFormat). This is simplified for easy understanding.
public static string Format(IFormatProvider provider, string format, params object[] args)
{
StringBuilder sb = new StringBuilder();
// Break up the format string into an array of tokens
Token[] tokens = ParseFormatString(format);
foreach (Token token in tokens)
{
switch (token.TokenType)
{
// A Text token is just some text to output directly
case TokenType.Text:
sb.Append(token.Text);
break;
// An Index token represents something like {0} or {2:format}
// token.Index is the argument index
// token.FormatText is the format string inside ('' in the first example, 'format' in the second example)
case TokenType.Index:
{
object arg = args[token.Index];
IFormattable formattable = arg as IFormattable;
if (formattable != null && token.FormatText.Length > 0)
{
// If the argument is IFormattable we pass it the format string specified with the index
sb.Append(formattable.ToString(token.FormatText, provider));
}
else
{
// Otherwise we just use Object.ToString
sb.Append(arg.ToString());
}
}
break;
}
}
return sb.ToString();
}
In your question you ask why the format string doesn't get applied when you pass "05-22-2012". As Guffa said, that is not a DateTime object, it is a String object.
As GSerjo said, a String is not IFormattable. Strings are not formattable because formatting is the process of converting something into a String. A string is already a string!
So you can see that when the Format method gets to indexer, arg will not be IFormattable and it will simply call ToString. Calling ToString on a string simply returns itself, it's already a string.
In summary, if your format string contains an index with an inner-format string (e.g. {0:format}), that inner-format string will only be applied if the associated argument is IFormattable and it knows what to do with the format string you give it.
A custom datetime format only works on a DateTime value. If you are using a string instead, the format will be ignored because there is only one way to output a string.
Because "05-22-2012" is not IFormattable, DateTime.Parse("05-22-2012") it's DateTime
please look here for more examples
String Format for DateTime
Custom Date and Time Format Strings

C# Replace is causing Object Reference Not Found error

using "Replace" on the string clientNameStr causes an "Object Reference Not Found" error.
// Get client name
clientName = currentUser.GetValue("ClientName");
string clientNameStr = (string)clientName;
string clientURLStr = string.Empty;
clientURLStr = clientNameStr.Replace(' ', '-');
// clientURLStr = "ST9215-Stanic-Parts-Ltd";
If I substitute in the commented out string (and comment out the existing one) it works fine, so it must be something to do with the replace function, but what? Have tried it with both " and ' quote marks, to the same result.
Any help would be greatly appreciated.
Thanks, Oli.
That basically shows that currentUser.GetValue("ClientName") is returning a null reference1.
We can't tell what currentUser.GetValue("ClientName") does, but there are two options:
It's correctly returning null, and you should handle that
It shouldn't return null, and you need to fix it (possibly to throw an exception if it encounters this situation)
1 It's possible that it's returning a non-null reference and using a user-defined conversion to string in the next line which returns null - but unlikely. We can't tell for sure because we don't know the type of the clientName .
Probably clientName (and thus clientNameStr) is null. You cannot call methods on the null object, even if you know that it should be a string.
It's possible that currentUser.GetValue("ClientName") is returning null, thus throwing an error when trying to execute the Replace.
Better coding would be
clientName = currentUser.GetValue("ClientName");
string clientNameStr = clientName ?? "";
string clientURLStr = clientNameStr.Replace(' ', '-');

.Trim() when string is empty or null

I'm receiving some data from the client in the form of json.
I'm writing this:
string TheText; // or whould it be better string TheText = ""; ?
TheText = ((serializer.ConvertToType<string>(dictionary["TheText"])).Trim());
If the variable that's being parsed from json comes back empty, does this code crash when I call the .Trim() method?
Thanks.
You can use elvis operator, also known as "null-conditional-operators":
GetNullableString()?.Trim(); // returns NULL or trimmed string
More info: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-conditional-operators
If the serializer returns an empty string, Trim will do nothing.
If the serializer returns null, you will get a NullReferenceException on the call to Trim.
Your code would be better written (as far as initialization is concerned) like this:
string theText =
((serializer.ConvertToType<string>(dictionary["TheText"])).Trim());
There is no point in declaring and initializing the variable and the immediately assigning to it.
The following would be safest, if you don't know what the serializer might return:
string theText = ((serializer.ConvertToType<string>(dictionary["TheText"])));
if(!string.IsNullOrEmpty(theText))
{
theText = theText.Trim();
}
Calling Trim() on an empty string will result in an empty string. Calling Trim() on null will throw NullReferenceException
If you have a few fields you wish to trim but your getting exceptions for those records that have nulls in certain fields, then writing a quick extension method will be the easiest method:
public static class ExtensionMethods
{
public static string TrimIfNotNull(this string value)
{
if (value != null)
{
return value.Trim();
}
return null;
}
}
Sample example of use:
string concatenated = String.Format("{0} {1} {2}", myObject.fieldOne.TrimIfNotNull(), myObject.fieldTwo.TrimIfNotNull(), myObject.fieldThree.TrimIfNotNull());
Some basic techniques to check strings against null before you trim:
(mystring ?? "").Trim()
The "null coalescing operator" ?? will return the first operand. Only when this operand is null, the second operand will be returned (as a kind of default value).
The above example will return an empty string if mystring is null.
mystring?.Trim()
The "null conditional operator" ? will short cirtuit a chain of operations in dot-notation. If the operand is null, the following operations will not be executed and null will be returned.
The above example will return null if mystring is null.
if( string.IsNullOrWhiteSpace(mystring) ) { ... }
the IsNullOrWhiteSpace() method may replace trimming if you actually want to check if there is real content in mystring. It returns true if the operand is null, empty, or nothing but whitespace characters.
As suggested in some of the comments, you may now use c# 6 Null-conditional operators with this syntax:
string TheText = (serializer.ConvertToType<string>(dictionary["TheText"]))?.Trim();
Documentation: https://msdn.microsoft.com/en-us/library/dn986595.aspx
No, it would not be better to initialize TheText to "". You're assigning to it right afterwards.
No, it won't crash – Trim() works just fine on an empty string. If by "empty" you mean that it can be null, then yes, it will crash; you could have null remain null with a null-conditional call:
string TheText =
serializer.ConvertToType<string>(dictionary["TheText"])?.Trim();
You can use the null-safe operator trim of org.apache.commons.lang
StringUtils.trim(stringOrNull)
You can use this code as beblow
string theText = (((serializer.ConvertToType<string>(dictionary["TheText"])))+ string.Empty).Trim();
Recently I had to check a string if it is null, empty or whitespace using just one if condition and for that I found out that you can add "" to a null string to make it non null.
string test = GetStringFromSomeWhere(); // null
if(string.IsNullOrEmpty(test.Trim())) { return true; } // Exception
So I did this instead
string test = GetStringFromSomeWhere() + ""; // ""
if(string.IsNullOrEmpty(test.Trim())) { return true; } // true

Specified cast is not valid exception in ms access query using C#

hey guys m having this wierd exception of cast though my datatypes are correct in db:
string sql =
string.Format(
#"select aim_network_id,aim_network_name,oxinetwork_id,pack_id,pack_name,p_face_value,pm_prefix from Operator where aim_network_id='{0}'",
gridbackOffice["aim_network_id", gridbackOffice.CurrentCell.RowIndex].Value);
OleDbCommand getSelectedGridDatecmd = new OleDbCommand(sql, conn);
OleDbDataReader reader = getSelectedGridDatecmd.ExecuteReader();
while (reader.Read())
{
txtAimNetworkID.Text = reader.GetString(0);
txtAimNetworkName.Text = reader.GetString(1);
txtPARNetworkID.Text = reader.GetString(2);
txtPARFaceValue.Text = reader["p_face_value"].ToString();
//in above line if i'm doing this `reader.GetString(5)` then i'm getting specified cast exception and that to randomly i.e some time it works fine and suddenly sometime gives this exception
txtPARPackID.Text = reader.GetString(3);
txtPARPackName.Text = reader.GetString(4);
txtPARPMPrefix.Text = reader["pm_prefix"].ToString();
}
I'm little bit confused if m using this reader["p_face_value"].ToString() then my code is running very smoothly but whats the issue with using this reader.GetString(5) , according to me both method return string, nebody had faced this error b4 ?
....Error is at 4th and 7th line in while loop.
Exception:Specified cast is not valid (InvalidCastException unhandled)
According to MSDN, OleDbDataReader.GetString() does not perform any conversions before attempting to cast to a string - therefore the data retrieved must already be a string.
If there is a chance that the value in that column could be null, the docs suggest that you should check if the value is null first:
if ( !reader.IsDBNull(5) ) {
txtPARFaceValue.Text = reader.GetString(5);
}
Calling reader["p_face_value"] on a null value returns DBNull - and when you call ToString() on DBNull, you get an empty string.
From MSDN:
No conversions are performed;
therefore the data retrieved must
already be a string.
If the column is not a string type, you'll need to use the .ToString() method to convert it.
What is the datatype of p_face_value in your database?
Based on the error description given it seems that this is not a string type, so when you call:
reader.GetString(5)
the code errors out as it cannot convert whatever type it is to a string. The .ToString() method will work as this does not use a cast.
You should use GetString only when the column is a string-equivalent type in the database (like varchar), in your case "p_face_value" seems to be a numeric type, therefore it cannot simply convert it to a string.
The way you're doing it right now is the right way.

Categories

Resources