Можно ли передать интерполированные строки в качестве параметра в метод?

Я начал использовать Interpolated Strings (новая функция С# 6), и это действительно полезно и изящно. Но согласно моим потребностям, я должен передать формат строки методу в качестве параметра. Что-то вроде следующего:

MyMethod(string format)

В прошлом я использовал его следующим образом:

MyMethod("AAA{0:00}")

Теперь я пробовал этот код:

MyMethod($"AAA{i:00}")

Но это не работает, потому что i создается внутри метода и в этом контексте выходит за рамки.

Можно ли использовать любой трюк для передачи интерполированных строк в качестве параметра к методу?

Ответ 1

Вы не можете этого сделать, и это тоже не очень хорошая идея - это означает, что вы используете локальные переменные из другого метода.
Это позволило бы превзойти цель этой функции - иметь подпрограммную интерпретацию строки и привязку к локальным переменным.

С# имеет несколько хороших альтернатив. Например, используя Func:

public void MyMethod(Func<int,string> formatNumber)
{
    int i = 3;
    var formatted = formatNumber(i);
}

использовать как:

MyMethod(number => $"AAA{number:00}");

Это лучше, чем у вас сегодня - где у вас есть строка формата (s?) и ее использование в разных местах.

Если у вас более одной переменной, этот подход может масштабироваться, но рассмотрим группировку в класс (или структуру) - Func будет выглядеть намного лучше, и ваш код будет более читабельным. Этот класс также может переопределить .ToString(), который может быть вам полезен.

Еще одна простая опция - передать только формат: MyMethod("00") и i.ToString(format), но это работает только в вашем предположительно упрощенном примере.

Ответ 2

Есть несколько способов сделать это.

Первым из них является добавление другой перегрузки метода, которая принимает FormattableString (новый тип, используемый одним из вариантов строковой интерполяции) и вызывает исходную:

public void MyMethod(FormattableString fs)
{
    MyMethod(fs.Format);
}

И вы также имеете доступ к аргументам, если вам нужно.

Если вам нужен только формат, просто создайте метод расширения, чтобы извлечь его:

public static string AsFormat(FormattableString fs)
{
    return fs.Format;
}

Ответ 3

Это невозможно. Но альтернативный способ -

public static string MyMethod(string format, params object[] args)
{
  if (format == null || args == null)
    throw new ArgumentNullException(format == null ? "format" : "args");
  return string.Format((IFormatProvider) null, format, args);
}

EDIT:

MyMethod("The number is {0}", 12);

EDIT2:

public static string MyMethod(string format)
{
    var i = 12;
    var result = string.Format(null, format, i);
    return result;
}
MyMethod("{0:000}");

Ответ 4

Несколько лет с тех пор, как это было спрошено, однако я наткнулся на это через Google, ища ответ, который у меня уже был у меня в голове, но не мог понять, как реализовать/синтаксис.

Мое решение - это то, что поставил @Kobi...

public class Person
    {
        public int Id {get; set;}
        public DateTime DoB {get;set;}
        public String Name {get;set;}
    }

public class MyResolver
{
    public Func<Person, string> Resolve {get;set;}
    public string ResolveToString<T>(T r) where T : Person
    {
        return this.Resolve(r);
    }
}

// code to use here...
var employee = new Person();
employee.Id = 1234;
employee.Name = "John";
employee.DoB = new DateTime(1977,1,1);

var resolver = new MyResolver();
resolver.Resolve = x => $"This person is called {x.Name}, DoB is {x.DoB.ToString()} and their Id is {x.Id}";

Console.WriteLine(resolver.ResolveToString(employee));

Я не тестировал выше для синтаксических ошибок, но, надеюсь, вы получите эту идею, и теперь вы можете просто определить, как вы хотите, чтобы строка выглядела, но оставляя пробелы для заполнения во время выполнения в зависимости от значений в вашем Объект Person.

Приветствия,

Вейн