Вопрос C#: почему я не могу назначить строку непосредственно классу, наследующему System.IFormattable или System.FormattableString, хотя они сами могут?
public class Program
{
public void Main()
{
IFormattable string1 = $"{1},{"test"}"; //Works
FormattableString string2 = $"{1},{"test"}"; //Works
LocStr string3 = $"{1},{"test"}"; ///Error: Cannot implicitly convert type 'string' to 'LocStr'
}
public class LocStr : IFormattable
{
public string ToString(string format, IFormatProvider formatProvider)
{
throw new NotImplementedException();
}
}
}
Я пытаюсь создать свой собственный класс FormattableString, однако независимо от того, наследует ли мой класс от IFormattable или FormattableString, его нельзя напрямую назначить из форматированной строки, как вLocStr testStr= $"Hello {User.Name}";
Я пробовал наследовать от IFormattable, FormattableString, но ничего не получилось.
Я проверил, могу ли я переопределить оператор присваивания =, но, по-видимому, это не разрешено в С#, как вpublic static LocStr operator =(string a)
но это не разрешено.
1 ответ
За кулисами творится какая-то магия компилятора. Если вы определяете тип переменной явно или разрешаете компилятору определять его с помощьюvar
тогда это приведет к типуstring
:
var string0 = $"{1},{"test"}";
Console.WriteLine(string0.GetType()); // System.String
Но для форматируемых строк существует также специальный тип:
Экземпляр может быть результатом интерполированной строки в C# или Visual Basic.
который вы действительно можете использовать в своем коде, что приводит к следующему поведению:
IFormattable string1 = $"{1},{"test"}"; //Works
FormattableString string2 = $"{1},{"test"}"; //Works
Console.WriteLine(string1.GetType()); // System.Runtime.CompilerServices.FormattableStringFactory+ConcreteFormattableString
Console.WriteLine(string2.GetType()); // System.Runtime.CompilerServices.FormattableStringFactory+ConcreteFormattableString
Демо @sharplab.io (также ознакомьтесь с декомпиляцией в C#).
На самом деле это описано в разделе «Неявные преобразования» и «Как указать».
IFormatProvider
раздел реализации документов:
Существует три неявных преобразования интерполированной строки:
- Преобразование интерполированной строки в
String
пример. ...- Преобразование интерполированной строки в
FormattableString
экземпляр, представляющий строку составного формата вместе с результатами выражения, подлежащими форматированию. ...- Преобразование интерполированной строки в экземпляр, который также позволяет создавать несколько строк результатов с содержимым, зависящим от культуры, из одной
IFormattable
пример. ...
Компилятор «из коробки» не знает, как преобразовать интерполированную строку в ваш конкретный тип, но начиная с C# 10 вы можете реализовать шаблон обработчика интерполированной строки (хотя в общем случае это не обязательно, обычно это необходимо для конкретных сценариев высокой производительности):
[InterpolatedStringHandler]
public class LocStr : IFormattable
{
public LocStr(int literalLength, int formattedCount)
{
}
public string ToString(string format, IFormatProvider formatProvider)
{
throw new NotImplementedException();
}
public void AppendLiteral(string s)
{
}
public void AppendFormatted<T>(T t)
{
}
}