Функция с параметром IFormattable не будет принимать строку

У меня есть функция, где я обработал строку ввода.

    public string Foo(string text)
    {
        // do stuff with text and
        // return processed string
    }

Я звонил из многих мест, где я конвертировал guid в строку вроде этого:

string returnValue = Foo(bar.ToString());

На самом деле я хотел принять в качестве входных данных любой тип объекта, который можно преобразовать в строку. Поэтому я попытался изменить функцию следующим образом:

    public string Foo(IFormattable text)
    {
        var textAsString = text.ToString();
        // do stuff with textAsString 
        // and return processed string
    }

Это означает, что все мои звонки проще:

string returnValue = Foo(bar);

Это работает для всех типов объектов, которые имеют метод.ToString; Кроме строк:)

Если я пытаюсь передать строку в функцию, я получаю следующую ошибку компиляции:

Argument type 'string' is not assignable to parameter type 'System.IFormattable'  

Что кажется странным, потому что в String есть метод ToString().

Почему это не работает?

3 ответа

Решение

Проще говоря, System.String не реализует IFormattable,

Если вам недостаточно документации:

object x = "a string";
Console.WriteLine(x is IFormattable); // False

При условии ToString() объявлен на object почему бы просто не иметь:

public string Foo(object text)
{
    var textAsString = text.ToString();
    // do stuff with textAsString 
    // and return processed string
}

Действительно, ToString() метод объявлен IFormattable это не тот, который вы пытались вызвать в любом случае - вы не передавали строку формата или поставщика формата.

Дополнительно:

Что кажется странным, потому что в String есть метод ToString().

Интерфейсы не имеют утки. Тот факт, что тип имеет все члены, необходимые для интерфейса, не означает, что он реализует интерфейс.

Прежде всего, IFormatable не влияет .ToString() это только внушает .ToString(string, IFormatProvider), С этими знаниями в руках, если вы все еще хотите использовать IFormatable самый простой способ справиться с этим - просто использовать перегрузки для ваших методов.

public string Foo(IFormattable text, string format, IFormatProvider formatProvider)
{
    return Foo(text.ToString(format, formatProvider));
}

public string Foo(IFormattable text, string format)
{
    return Foo(text.ToString(format, null));
}

public string Foo(string text)
{
    // do stuff with text and
    // return processed string
}

String не реализует IFormattable, но ваш код тоже не использует его. Вы можете создать класс-оболочку для string для использования в сценариях, где IFormattable нужно, вот так:

public class FormattableString : IFormattable {
    private readonly string str;
    public FormattableString(string str) {
        this.str = str;
    }
    public string ToString() {
        return str;
    }
    public string ToString(string format, IFormatProvider formatProvider) {
        // You can add special code here to format the value of your string
        // as directed by the format passed into the method.
        return str;
    }
}

Теперь вы можете использовать этот класс следующим образом:

string returnValue = Foo(new FormattableString(bar));
Другие вопросы по тегам