Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implicit conversion to String/string inside interpolated string

So I stumbled upon the following:

Console.WriteLine(currentRow["Projekt"]);
Console.WriteLine($"{currentRow["Projekt"]}");
Console.WriteLine($"{(string)currentRow["Projekt"]}");

With the output:

> Data that i want
> Namespace.ExcelDataField
> Data that i want

Where ExcelDataField is obviously a class I wrote to help me read data out of an excel sheet. I tried to implement this to resemble VBAs DAO access with MoveFirst/Next and always expose 1 row of data (currentRow).

I used a class ExcelDataField to encapsulate the data coming out of my excel sheet because the type will be dynamic when reading.

public class ExcelDataField<T>
{
    private Excel.Range m_XlRange;
    private int m_Row;
    private int m_Col;

    public T Data
    {
        get
        {
            return (T)(this.m_XlRange.Cells[this.m_Row, this.m_Col] as Excel.Range)?.Value2;
        }

        set
        {
            this.m_XlRange.Cells[this.m_Row, this.m_Col] = value;
        }
    }

    public ExcelDataField(Excel.Range range, int row, int col)
    {
        this.m_XlRange = range;
        this.m_Row = row;
        this.m_Col = col;
    }

    public static implicit operator T(ExcelDataField<T> dataField)
    {
        return dataField.Data;
    }
}

Currently I am assuming for testing purposes that all data can later easily be handled as a string so I made an overload of this class ExcelDataField : ExcelDataField<string> which is the class I am using to read an excel sheet into. in the example, I am just reading it back to console.

Everything works fine as long as I am not using interpolated strings which obviously don't find my implicit conversion. I tried to change ExcelDataField : ExcelDataField<string> to ExcelDataField : ExcelDataField<String> but both don't work.

In my understanding interpolated strings use the FormattableString type which doesn't have any implicit conversion from string or String only explicit.

My question would be can anyone explain in greater detail what exactly is going on here and is there a clean way for me to able to use interpolated strings?

like image 561
Robin B Avatar asked Nov 09 '17 13:11

Robin B


2 Answers

It is fairly easy. $"{currentRow["Projekt"]}" is just the same as string.Format("{0}", currentRow["Projekt"]). On the object instance provided by currentRow["Projekt"], the ToString method is called. The default implementation on object is that it returns the type name.

So basically all you have to do is to override that behavior. You can do that by overriding the ToString method:

public override string ToString()
{
    return dataField.Data?.ToString();
}
like image 132
Patrick Hofman Avatar answered Oct 13 '22 00:10

Patrick Hofman


Interpolated strings will either be compiled into a string.Format(...) expression, or compiled into a wrapper class FormattableString that internally uses string.Format(...)

Here's a rundown of the options considered for each such parameter:

  1. Does the IFormatProvider given to string.Format(...) return a ICustomFormatter when asked? If yes then consult ICustomFormatter.Format for each value first.
  2. Does the type of the parameter value implement IFormattable? If yes, then IFormattable.ToString is called
  3. If no, then the .ToString() method is called directly on the value

So in your case, your best option is probably to just override ToString().

The exact code (at least in reference source) is inside StringBuilder, found here: StringBuilder.cs, line 1441 - AppendFormatHelper method.

like image 31
Lasse V. Karlsen Avatar answered Oct 13 '22 00:10

Lasse V. Karlsen