25 stycznia 2010, 00:43 dario Komentarze (0)

FormatWith - inne implementacje

Łukasz Kurzyniec wspomniał o bardzo fajnym sposobie formatowania stringa, gdzie zamiast kolejnych indeksów {0}, {1}, itd podaje się nazwy właściwości, a jako źródło obiekt je posiadający. Niestety nie mogłem dodać komentarza na blogu Łukasza, stąd ten post. Swego czasu Phill Haack zainteresował się tym tematem i pokazał inne implementacje. Obecnie dzięki Niemu używam implementacji Henri'ego, która to mimo większej ilości kodu okazała się najszybsza.

Dodatkowo w swojej implementacji dodałem jedno przeciążenie, dzięki któremu możemy określi czy brak właściwości odpowiadającej znalezionemu parametrowi ma wyrzucić wyjątek czy też nie. Przydatne przy bardziej zaawansowanym formatowaniu/parsowaniu.

Poniżej przeklejam kod, aby nigdzie się nie zgubił ;) Acha, u mnie ta metoda nazywa się FormatNamed.

public static string FormatNamed(this string format, object source)
{
    return FormatNamed(format, source, false);
}
public static string FormatNamed(this string format, object source, bool ignoreNotFound)
{
    if (format == null)
    {
        throw new ArgumentNullException("format");
    }
    StringBuilder result = new StringBuilder(format.Length * 2);
    using (var reader = new StringReader(format))
    {
        StringBuilder expression = new StringBuilder();
        int @char = -1;
        State state = State.OutsideExpression;
        
        do
        {
            switch (state)
            {
                case State.OutsideExpression:
                    @char = reader.Read();
                    switch (@char)
                    {
                        case -1:
                            state = State.End;
                            break;
                        case '{':
                            state = State.OnOpenBracket;
                            break;
                        case '}':
                            state = State.OnCloseBracket;
                            break;
                        default:
                            result.Append((char)@char);
                            break;
                    }
                    break;
                case State.OnOpenBracket:
                    @char = reader.Read();
                    switch (@char)
                    {
                        case -1:
                            throw new FormatException();
                        case '{':
                            result.Append('{');
                            state = State.OutsideExpression;
                            break;
                        default:
                            expression.Append((char)@char);
                            state = State.InsideExpression;
                            break;
                    }
                    break;
                case State.InsideExpression:
                    @char = reader.Read();
                    switch (@char)
                    {
                        case -1:
                            throw new FormatException();
                        case '}':
                            result.Append(OutExpression(source, expression.ToString(), ignoreNotFound));
                            expression.Length = 0;
                            state = State.OutsideExpression;
                            break;
                        default:
                            expression.Append((char)@char);
                            break;
                    }
                    break;
                case State.OnCloseBracket:
                    @char = reader.Read();
                    switch (@char)
                    {
                        case '}':
                            result.Append('}');
                            state = State.OutsideExpression;
                            break;
                        default:
                            throw new FormatException();
                    }
                    break;
                default:
                    throw new InvalidOperationException("Invalid state.");
            }
        } while (state != State.End);
    }
 
    return result.ToString();
}
 
private static string OutExpression(object source, string expression, bool ignoreNotFound)
{
    string format = "";
    string orygexpression = expression;
 
    int colonIndex = expression.IndexOf(':');
    if (colonIndex > 0)
    {
        format = expression.Substring(colonIndex + 1);
        expression = expression.Substring(0, colonIndex);
    }
 
    try
    {
        if (String.IsNullOrEmpty(format))
        {
            return (DataBinder.Eval(source, expression) ?? "").ToString();
        }
        return DataBinder.Eval(source, expression, "{0:" + format + "}") ?? "";
    }
    catch (HttpException)
    {
        if (!ignoreNotFound)
        {
            throw new FormatException();
        }
        else
        {
            return orygexpression;
        }
    }
}
 
private enum State
{
    OutsideExpression,
    OnOpenBracket,
    InsideExpression,
    OnCloseBracket,
    End
}

Tagi:

Tip

Komentarze zablokowane

O autorze

Dariusz Gil - projektant i programista aplikacji internetowych budowanych na platformie Microsoft w technologii ASP.NET (C#) oraz MS SQL Server. Obecnie właściciel (narazie :)) jednoosobowej firmy Softio.

Filtruj używając APML