Mr. Boy
Mr. Boy

Reputation: 63778

How can I get the string interpolation operator $ to print "null" for null parameters?

string o=null;
Console.WriteLine($"Hello World '{o}'");

This outputs:

Hello World ''

I would like to explicitly write "null" for null values.

string o=null;
Console.WriteLine($"Hello World '{o??"null"}'");

This does just that:

Hello World 'null'

But if o is not of type string (or Object) it generates a compilation error. For example:

Array o=null;
Console.WriteLine($"Hello World '{o??"null"}'");

Compilation error Operator '??' cannot be applied to operands of type 'Array' and 'string'

What is the best way to achieve the desired outcome? It's a shame you cannot modify how $ handles null as it appears hard-coded to use String.EmptyString

Upvotes: 2

Views: 1843

Answers (3)

Super Jade
Super Jade

Reputation: 6364

I'm not sure what you want to print if your variable is not null, but you could try the ternary conditional operator

Array o = null;
Console.WriteLine($"Hello World '{(o == null ? "null" : "not null")}'");

or

Array o = null;
Console.WriteLine($"Hello World '{(o == null ? "null" : o.ToString())}'");

depending on what o is and whether you have overridden ToString().


Related:

How to print the null values if the dictionary has it using LINQ

Upvotes: 0

Caius Jard
Caius Jard

Reputation: 74660

You can leverage that $ can turn your string into a formattablestring and you can provider a custom formatted that it will call when it processes each arg in turn. Like providing a custom comparer to a sort function


class NullyFormatProvider : IFormatProvider
{
    private readonly NullyFormatter _formatter = new NullyFormatter();

    public object GetFormat(Type formatType)
    {
        if (formatType == typeof(ICustomFormatter))
            return _formatter;
        return null;
    }

    class NullyFormatter : ICustomFormatter
    {
        public string Format(string format, object arg, IFormatProvider formatProvider)
        {
            if (arg == null)
                return "arg was null, bro!";
            else
                return arg.ToString();
        }
    }
}

You can trigger your null format provider by passing it through a function that will make c# treat it as a formattable string (rather than the compiler straight calling string format on it for example) :

static string NullyVersion(FormattableString formattable)
{
    return formattable.ToString(new NullyFormatProvider());
}

...

Array o = null;
string txt = NullyVersion($"check out this array: {o}");

Of course, you wouldn't make it this lengthy/you probably wouldn't use NullyVersion to create a string to use where you wanted a string.. you'd make your e.g. "logging method that takes a string" take a FormattableString instead and then format it with the nully formatter perhaps like:

static string Log(FormattableString formattable)
{
    Console.WriteLine( formattable.ToString(new NullyFormatProvider()); //or some instance of NFP
}

Then you can just use in your code like you wanted at the outset:

Array o = null;
Log($"Data was {o}");

I haven't looked too deep into how to check whether you're passed something that takes a format - you'll note that the Format() method in the ICustomFormatter takes a string format - if you wrote Log($"it is now {DateTime.Now:yyyyMMdd} woo") then the object arg would be the datetime, and the string format would contain "yyyyMMdd" - it can be anything you want. You could define your own:

int[] nums = {1,2,3};
Log($"those nums are {nums:csv}");

And in your Format:

if(format == "csv" && arg is int[] x)
  //turn the passed in arg (an int array inside an obj) into some csv representation...
  return string.Join(",", x.Select(e => e.ToString()));

For more details take a look at ICustomFormatter https://learn.microsoft.com/en-us/dotnet/api/system.icustomformatter?view=netcore-3.1

Upvotes: 4

Bizhan
Bizhan

Reputation: 17095

You can cast "null" to object so that ?? can be applied to all types of operands.

$"Hello World '{o ?? (object)"null"}'"

Upvotes: 8

Related Questions