Включить оператор If Else в String.Format - PullRequest
8 голосов
/ 18 августа 2010

У меня есть следующее состояние.

  timespan = timespan.FromSeconds(236541)
  formattedTimeSpan = String.Format("{0} hr {1} mm {2} sec", Math.Truncate(timespan.TotalHours), timespan.Minutes, timespan.Seconds)

Мне нужно отформатировать его как "hrs mn sec", если есть более одного часа. Я хочу проверить это в формате String.Format выше.

Спасибо.

Ответы [ 7 ]

9 голосов
/ 18 августа 2010

Вероятно, самый чистый способ сделать это - написать свой собственный ICustomFormatter.Вот пример удобного формата мультипликатора:

using System;

public class PluralFormatter : IFormatProvider, ICustomFormatter {

   public object GetFormat(Type formatType) {
      if (formatType == typeof(ICustomFormatter))
         return this;
      else
         return null;
   }

   public string Format(string format, object arg, 
                          IFormatProvider formatProvider)
   {   
      if (! formatProvider.Equals(this)) return null;

      if (! format.StartsWith("^")) return null;

      String[] parts = format.Split(new char[] {'^'});
      int choice = ((int) arg) == 1 ? 1 : 2;
      return String.Format("{0} {1}", arg, parts[choice]);
   }

   public static void Main() {
      Console.WriteLine(String.Format(
         new PluralFormatter(),
         "{0:^puppy^puppies}, {1:^child^children}, and {2:^kitten^kittens}", 
         13, 1, 42
      ));
   }
}

Вывод, как можно было догадаться ( и как видно на ideone.com ):

13 puppies, 1 child, and 42 kittens

Ссылки MSDN

7 голосов
/ 18 августа 2010

Одной из возможностей является создание множественной части строки формата и запись:

formattedTimeSpan = String.Format("{0} hr{1} {2} mm {3} sec",
    Math.Truncate(timespan.TotalHours),
    Math.Truncate(timespan.TotalHours) == 1 ? "" : "s",
    timespan.Minutes,
    timespan.Seconds);

Это вставит «s» в вывод, если в выводе будет указано что-то отличное от «1 часа».

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

3 голосов
/ 18 августа 2010

Я использую несколько методов расширения, которые помогают мне с такими вещами:

public static string Inflect(this string noun, int count)
{
 return (count == 1 || noun.EndsWith("s", StringComparison.InvariantCultureIgnoreCase)) ? noun : noun + "s";
}

public static string Of(this int count, string noun)
{
 return string.Format("{0} {1}", count, noun.Inflect(count));
}

например:.

"Hour".Inflect(1): час

"Hour".Inflect(2): часы

0.Of("hour"): "0 часов"

1.Of("hour"): "1 час"

5.Of("hour"): "5 часов"

3 голосов
/ 18 августа 2010

Никакой магии здесь. Зачем вам кодировать в любых условиях, которые может предложить format, когда вы можете писать на C #?

Чтобы избежать дублирования кода, вы могли бы выдвигать некоторые выражения к переменным и использовать для них условие:

timespan = timespan.FromSeconds(236541);
int hours = Math.Truncate(timespan.TotalHours);
string hoursUnit = hours == 1 ? "hr" : "hrs";
formattedTimeSpan = String.Format("{0}{1} {2} mm {3} sec",
                        hours, hoursUnit, timespan.Minutes, timespan.Seconds);
2 голосов
/ 18 августа 2010

Вы должны использовать различные спецификаторы формата времени. Это помогает упростить вызов Format().

var timespan = TimeSpan.FromSeconds(236541);
var formattedTimeSpan = String.Format("{0:hh} hr{1} {0:mm} mm {0:ss} sec",
    timespan, timespan.Hours != 1 ? "s" : "");
0 голосов
/ 18 августа 2010

FWIW, если ваше приложение будет использовать мои не говорящие на английском языке когда-либо, то это что-то не тривиальное. Есть сообщение в блоге, которое излагает проблему в http://www.siao2.com/2007/07/24/4022881.aspx

0 голосов
/ 18 августа 2010

Нет "простого" способа сделать это.

Вы можете сделать это так

string templateSingleHour = "{0} hr {1} mm {2} sec";
string templateMultiHour = "{0} hrs {1} mm {2} sec";
string template = Math.Truncate(timespan.TotalHours) > 1 ? templateMultiHour :templateSingleHour;
formattedTimeSpan = String.Format(template ...)

или как это

formattedTimeSpan = String.Format("{0} {3} {1} mm {2} sec", Math.Truncate(timespan.TotalHours), timespan.Minutes, timespan.Seconds, Math.Truncate(timespan.TotalHours) > 1 ? "hrs" : "hr");
...