IFormattableからフォーマットとバインドされている値を取得する

リフレクションで非publicメンバから無理やり取得した。 他に方法あるのかな

取得するメソッド

public static class FormattableStringDissolver
{
  private static FieldInfo FormatField;
  private static FieldInfo ArgumentsField;

  static FormattableStringDissolver()
  {
    IFormattable formattableString = $"";
    var type = formattableString.GetType();
    FormatField = type.GetField("_format", BindingFlags.NonPublic | BindingFlags.Instance);
    ArgumentsField = type.GetField("_arguments", BindingFlags.NonPublic | BindingFlags.Instance);
  }

  /// <summary>
  /// <see cref="IFormattable"/>からフォーマットの文字列と
  /// バインドされている値の全てをリフレクションで強制的に取り出します。
  /// </summary>
  /// <param name="formattableString"></param>
  /// <returns>フォーマットとバインドされている全ての値</returns>
  public static (string format, object[] args) Dissolve(IFormattable formattableString)
  {
    if (formattableString == null)
    {
      throw new ArgumentNullException(nameof(formattableString));
    }

    var format = FormatField.GetValue(formattableString);
    var arguments = ArgumentsField.GetValue(formattableString);

    return (format as string, arguments as object[]);
  }
}

テスト

[TestClass]
public class Test
{
  [TestMethod]
  public void Test_FormattableStringDissolver_Dissolve()
  {
    int number = 123;
    IFormattable src = $"{number}, {number}, {"abc"}";
    (string format, object[] bindedObjects) = FormattableStringDissolver.Dissolve(src);

    Assert.AreEqual(format, "{0}, {1}, {2}");
    Assert.AreEqual(number, bindedObjects[0]);
    Assert.AreEqual(number, bindedObjects[1]);
    Assert.AreEqual("abc", bindedObjects[2]);
  }
}
Share