.NET: Gibt es eine String.Format Form den Wert einer Objekteigenschaft in einen String zum Einfügen?

StackOverflow https://stackoverflow.com/questions/357447

  •  21-08-2019
  •  | 
  •  

Frage

Ich denke, die direkte Antwort auf die Frage ‚Nein‘, aber ich bin die Hoffnung, dass jemand eine wirkliche einfache Bibliothek, dies zu tun geschrieben hat (oder ich kann es tun ... igitt ...)

Lassen Sie mich zeigen, was ich suche mit einem Beispiel. Angenommen, ich hatte die folgende:

class Person {
  string Name {get; set;}
  int NumberOfCats {get; set;}
  DateTime TimeTheyWillDie {get; set;}
}

Ich möchte in der Lage sein, so etwas zu tun:

static void Main() {
  var p1 = new Person() {Name="John", NumberOfCats=0, TimeTheyWillDie=DateTime.Today};
  var p2 = new Person() {Name="Mary", NumberOfCats=50, TimeTheyWIllDie=DateTime.Max};

  var str = String.Format(

"{0:Name} has {0:NumberOfCats} cats and {1:Name} has {1:NumberOfCats} cats.  They will die {0:TimeTheyWillDie} and {1:TimeTheyWillDie} respectively
", p1, p2);

  Console.WriteLine(str);
}

Wer weiß, ob noch ein Format für so etwas wie dieses oder wenn jemand tun geschrieben hat es eine Bibliothek zu tun? Ich weiß, es sollte nicht allzu schwer sein, aber ich würde lieber das Rad nicht sein Neuimplementierung.

War es hilfreich?

Lösung

Edit: Sie müssen nicht IFormattable für jedes Objekt implementieren ... das wäre ein PITA, streng zu begrenzen, und ein ziemlich großer Wartungsaufwand sein. Verwenden Sie einfach Reflexion und eine IFormatProvider mit ICustomFormatter und es wird funktionieren mit jeder Objekt. String.Format hat eine Überlastung eine als Parameter zu nehmen.

Ich habe noch nie daran gedacht, aber man hat mich fasziniert - so hatte ich ihm einen schnellen Wirbel zu geben. Beachten Sie, dass ich wählte ein zusätzliches Format-String zu ermöglichen, auf die Eigenschaft Wert zu übergeben, und dass es funktioniert nur mit nicht indexiert und zugänglich Eigenschaften (obwohl man leicht, dass hinzufügen könnte).

public class ReflectionFormatProvider : IFormatProvider, ICustomFormatter {
    public object GetFormat(Type formatType) {
        return formatType == typeof(ICustomFormatter) ? this : null;
    }

    public string Format(string format, object arg, IFormatProvider formatProvider) {
        string[] formats = (format ?? string.Empty).Split(new char[] { ':' }, 2);
        string propertyName = formats[0].TrimEnd('}');
        string suffix = formats[0].Substring(propertyName.Length);
        string propertyFormat = formats.Length > 1 ? formats[1] : null;

        PropertyInfo pi = arg.GetType().GetProperty(propertyName);
        if (pi == null || pi.GetGetMethod() == null) {
            // Pass thru
            return (arg is IFormattable) ? 
                ((IFormattable)arg).ToString(format, formatProvider) 
                : arg.ToString();
        }

        object value = pi.GetGetMethod().Invoke(arg, null);
        return (propertyFormat == null) ? 
            (value ?? string.Empty).ToString() + suffix
            : string.Format("{0:" + propertyFormat + "}", value);
    }
}

Und Ihr leicht modifizierten Beispiel:

var p1 = new Person() {Name="John", NumberOfCats=0, TimeTheyWillDie=DateTime.Today};
var p2 = new Person() {Name="Mary", NumberOfCats=50, TimeTheyWillDie=DateTime.MaxValue};

var str = string.Format(
    new ReflectionFormatProvider(),
    @"{0:Name} has {0:NumberOfCats} cats and {1:Name} has {1:NumberOfCats} cats. 
    They will die {0:TimeTheyWillDie:MM/dd/yyyy} and {1:TimeTheyWillDie} respectively.
    This is a currency: {2:c2}.", 
    p1, 
    p2,
    8.50M
);

Console.WriteLine(str);

Ausgänge:

John has 0 cats and Mary has 50 cats. 
They will die 12/10/2008 and 12/31/9999 11:59:59 PM respectively.
This is a currency: $8.50.

Andere Tipps

Sie können die ToString () für Ihre Klasse außer Kraft setzen.

Good Artikel hier

Was ist nach dem „:“ als Argument für die ToString-Methode Ihrer Klasse übergeben wird
. Nur eine ToString-Methode deklariert einen String zu akzeptieren, und den ‚Namen‘, ‚NumberOfCats‘ usw. wird in diesem Parameter übergeben werden.

EDIT: Sie müssen System.IFormattable implementieren. Dies funktioniert:

class Person : IFormattable
{
    public override string ToString()
    {
        return "Person";
    }

    public string ToString(string format, IFormatProvider formatProvider)
    {
        if (format == "Name")
        {
            return "John";
        }
        if (format == "NumberOfCats")
        {
            return "12";
        }
        return "Unknown format string";
    }

}

class Program
{
    static void Main(string[] args)
    {
        Person p = new Person();
        Console.WriteLine(string.Format("Name = {0:Name}",p));
        Console.WriteLine(string.Format("NumberOfCats = {0:NumberOfCats}", p));
    }
}

Sehen Sie sich meine Bibliothek "Expansive"

Auf Nuget hier: http://nuget.org/List/Packages/Expansive

Auf GitHub hier: http://github.com/anderly/expansive

ich wirklich nicht sehen, wie folgt aus:

"{0:Name} has {0:NumberOfCats} cats and {1:Name} has {1:NumberOfCats} cats.  They will die {0:TimeTheyWillDie} and {1:TimeTheyWillDie} respectively", p1, p2);

ist besser als diese:

"{0} has {1} cats and {2} has {3} cats.  They will die {4} and {5} respectively
", p1.Name, p1.NumberOfCats, p2.Name, p2.NumberOfCats, p1.TimeTheyWillDie, p2.TimeTheyWillDie);

In der Tat, da Sie Intellisense Hilfe in dem ersten sind zu verlieren, ist es nicht nur anfälliger für Scheitern würde aber wahrscheinlich länger dauern, in einer IDE zu schreiben.

Und wenn Sie so etwas wie dies tun wollen, können Sie immer eine Erweiterungsmethode für sie schüren. Ich wette, es wie ein Alptraum aussehen würde, tho.

Boo oder Nemerle hat so etwas wie dieses. Ich habe versucht, eine schöne einfache Art und Weise zu denken, dass es für ein paar Jahre zu tun, jetzt, wo keine einfache Antwort.

Das Beste, was Sie tun können, sind Sie IFormatProvider besitzen, und analysiert, um die Eingabe manuell (das beschissene Teil ...).

Wenn Sie den Format-String selbst zu analysieren, sollten Sie dies berücksichtigen ...:

Das Spring.NET Projekt hat das Spring.NET Expression Language in Spring.Core. Damit können Sie ein Objektgraph Abfrage mithilfe Strings Eigenschaften zeigen. Mit Ihrem Beispiel Sie so etwas wie dies vorstellen kann:

var person = new Person { Name = "joe", Email = new Email { Address = "joe@joe.com" } };

var message = string.Format("{0}'s e-mail is {1}",
    ExpressionEvaluator.GetValue(person, "Name"), 
    ExpressionEvaluator.GetValue(person, "Email.Address"));

(ich würde wahrscheinlich nicht speichern Sie eine E-Mail so, aber ich konnte nicht mit etwas besser kommen)

Dies ist etwas, das viele in der Python-Welt zu tun, indem Sie „somestring% Einheimischen ().“ Was Sie vorschlagen hat allerdings ein paar grundlegende Pausen aus, wie string.format Werke:

  • normalerweise die Platzhalter-Notation hat String Formatierungsinformationen nach dem Doppelpunkt, während Sie den Zugriff auf Eigenschaften machen will.

  • Die Platzhalter-Indizes ({0, {1, usw.) beziehen sich normalerweise auf die Numberes Argumente in den params args, aber es scheint, dass Sie Ihre Funktion möchten die gesamte Zeichenfolge für jeden Parameter zu machen, die in übergeben wird. sollten sie verkettet werden? kehrt als String-Array?

So können Sie am Ende dieses ein Schreiben selbst, in dem Fall, dass Sie die Index-Notation ganz überspringen kann (so {NumberOfCats} statt {0: NumberOfCats} oder sogar Eigenschaftsnamen von Format-Provider gefolgt verwenden {NumberOfCats: c}. die Metadaten aus einem Eingabeobjekt Consuming sollte nicht zu hart sein.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top