在内插字符串中隐式转换为 String/string

Implicit conversion to String/string inside interpolated string

所以我偶然发现了以下内容:

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

输出:

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

其中 ExcelDataField 显然是 class 我写的是为了帮助我从 excel sheet 中读取数据。我试图实现它以类似于使用 MoveFirst/Next 的 VBA DAO 访问,并且始终公开 1 行数据 (currentRow)。

我使用 class ExcelDataField 来封装来自 excel sheet 的数据,因为读取时类型将是 dynamic

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

目前,出于测试目的,我假设所有数据以后都可以轻松地作为字符串处理,所以我重载了这个 class ExcelDataField : ExcelDataField<string>,这就是我的 class用来读入 excel sheet 。在示例中,我只是将其读回控制台。

只要我不使用显然找不到我的隐式转换的内插字符串,一切都可以正常工作。我尝试将 ExcelDataField : ExcelDataField<string> 更改为 ExcelDataField : ExcelDataField<String>,但两者均无效。

在我的理解中,内插字符串使用 FormattableString 类型,它没有任何从字符串或字符串的隐式转换,只有显式的。

我的问题是任何人都可以更详细地解释这里到底发生了什么吗?有没有一种干净的方法让我能够使用内插字符串?

这很容易。 $"{currentRow["Projekt"]}"string.Format("{0}", currentRow["Projekt"]) 相同。在 currentRow["Projekt"] 提供的 object 实例上,调用了 ToString 方法。 object 上的默认实现是 returns 类型名称。

所以基本上您所要做的就是覆盖该行为。您可以通过覆盖 ToString 方法来做到这一点:

public override string ToString()
{
    return dataField.Data?.ToString();
}

内插字符串将编译成 string.Format(...) 表达式,或编译成内部使用 string.Format(...)

的包装器 class FormattableString

以下是为每个此类参数考虑的选项的概要:

  1. IFormatProvider string.Format(...) return 被问到 ICustomFormatter 了吗?如果是,则首先针对每个值咨询 ICustomFormatter.Format
  2. 参数值的类型是否实现IFormattable?如果是,则IFormattable.ToString被称为
  3. 如果没有,那么.ToString()方法直接在值
  4. 上调用

所以在你的情况下,你最好的选择可能是覆盖 ToString().

确切的代码(至少在参考源中)在 StringBuilder 内,找到 here: StringBuilder.cs, line 1441 - AppendFormatHelper method