2010-03-10 6 views
14

En el mundo de Java tenemos Apache Commons 'ToStringBuilder para ayudar a crear implementaciones toString().¿Hay un equivalente a ToStringBuilder de Java para C#? ¿Qué característica de una buena versión de C#?

¿Alguien sabe de una implementación libre decente para C#? ¿Hay mejores alternativas que yo no sepa?

Si no existe una implementación libre que supongo que esta pregunta se convierte más en una pregunta de "¿Qué haría un buen ToStringBuilder en C# 3?"

De la parte superior de mi cabeza:

  • que podría ofrecer la reflexión y la creación cadena ToString manual.

  • Sería genial si pudiera hacer uso de los árboles Expression.

Algo como esto ..

public override string ToString() 
    { 
     return new ToStringBuilder<Foo>(this) 
     .Append(t => t.Id) 
     .Append(t => t.Name) 
     .ToString(); 
    } 

cual se devolvía:

"Foo{Id: 1, Name: AName}" 
  • Podría utilizar System.Reflection.Emit precompilar un delegado ToString.

¿Alguna otra idea?

ACTUALIZACIÓN

Solo para aclarar ToStringBuilder es una criatura diferente a StringBuilder .. Estoy buscando algo similar a la funcionalidad de ToStringBuilder de Apache Commons, tiene características como el formato de múltiples líneas, diferente estilos y base de reflexión creación ToString. Gracias.

ACTUALIZACIÓN 2

he construido mi propia. Ver here.

+0

Quizás debas haber vinculado a la descripción de lo que hace ToStringBuilder: http://commons.apache.org/lang/api/org/apache/commons/lang/builder/ToStringBuilder.html – Powerlord

+0

@Powerlord, gracias por haber actualizado el enlace, supongo que no a todos les gusta tanto el código fuente de Grokking como yo ;-) – chillitom

+0

Versión rápida C# 4 agregada a continuación: http://stackoverflow.com/questions/2417647/is- there-an-equivalent-to-javas-tostringbuilder-for-c-what-would-a-good-c-ver/4959343 # 4959343 – chillitom

Respuesta

13

EDIT: OK, que desea utilizar la reflexión para que no tenga que escribir los nombres de propiedades.Creo que esto le conseguirá lo que busca:

// forgive the mangled code; I hate horizontal scrolling 
public sealed class ToStringBuilder<T> { 
    private T _obj; 
    private Type _objType; 
    private StringBuilder _innerSb; 

    public ToStringBuilder(T obj) { 
     _obj = obj; 
     _objType = obj.GetType(); 
     _innerSb = new StringBuilder(); 
    } 

    public ToStringBuilder<T> Append<TProperty> 
    (Expression<Func<T, TProperty>> expression) { 

     string propertyName; 
     if (!TryGetPropertyName(expression, out propertyName)) 
      throw new ArgumentException(
       "Expression must be a simple property expression." 
      ); 

     Func<T, TProperty> func = expression.Compile(); 

     if (_innerSb.Length < 1) 
      _innerSb.Append(
       propertyName + ": " + func(_obj).ToString() 
      ); 
     else 
      _innerSb.Append(
       ", " + propertyName + ": " + func(_obj).ToString() 
      ); 

     return this; 
    } 

    private static bool TryGetPropertyName<TProperty> 
    (Expression<Func<T, TProperty>> expression, out string propertyName) { 

     propertyName = default(string); 

     var propertyExpression = expression.Body as MemberExpression; 
     if (propertyExpression == null) 
      return false; 

     propertyName = propertyExpression.Member.Name; 
     return true; 
    } 

    public override string ToString() { 
     return _objType.Name + "{" + _innerSb.ToString() + "}"; 
    } 
} 

Ejemplo:

// from within some class with an Id and Name property 
public override string ToString() { 
    return new ToStringBuilder<SomeClass>(this) 
     .Append(x => x.Id) 
     .Append(x => x.Name) 
     .ToString(); 
} 

He aquí, el comportamiento que está buscando:

class Thing { 
    public int Id { get; set; } 
    public string Name { get; set; } 

    public override string ToString() { 
     return new ToStringBuilder<Thing>(this) 
      .Append(t => t.Id) 
      .Append(t => t.Name) 
      .ToString() 
    } 
} 

void Main() { 
    var t = new Thing { Id = 10, Name = "Bob" }; 
    Console.WriteLine(t.ToString()); 
} 

Salida:

Thing {Id: 10, Nombre: "Bob"}

+2

no es tan bueno, tiene literales de cadenas y no sobrevivirá a la refactorización –

+0

Gracias Dan es una buena solución ajustada. Sería genial si pudiéramos ampliar la versión de Java y usar expresiones para deshacernos de la cadena de nombre, de esa manera el código sería a prueba de refactor. – chillitom

+0

@chillitom: lo di un golpe - échele un vistazo. –

1

Utilice .NET StringBuilder.

Tenga en cuenta que tendrá que proporcionar una pequeña plantilla usted mismo.

por ejemplo:

public StringBuilder ToStringBuilder<T>(T type) where T : IYourInterface 
{ 
StringBuilder sb = new StringBuilder(); 
sb.append(type.key); 
// more appends 

return sb; 
} 

proporcionado una manera un poco generic aquí. Vas a ser capaz de crear su propia solución ordenada con el espacio de nombres en .NET System.Reflection

Saludos

+0

gracias pero estoy buscando algo bastante diferente, el generador de cadenas es bueno pero requiere mucho más injertar para hacer una ToString bonita que hace Apache Commons ToStringBuilder de Java. – chillitom

+0

lo vio, podría intentar hacer su propio método ToStringBuilder que envuelva a un generador de cadenas .. –

+0

El método que publicó solo devuelve una cadena. –

1

ver este proyecto ...

http://commonsdotnet.codeplex.com/

+0

gracias mxmissile, sabía que algo tenía que existir en alguna parte. Sin embargo, es un poco decepcionante, después de ver la fuente supongo que esta se dirige a las versiones 2 y siguientes de C#. Es muy diferente de la clase Java, es solo un montón de llamadas estáticas y requiere que los nombres de campo se pasen como una lista de cadenas, algo mucho más agradable seguramente es posible con C# 3. – chillitom

+0

sí, acabo de notar que, lo juro Lo he visto en alguna parte, pensé que ese era el lugar. Seguiré buscando, podría usar algo como esto también. – mxmissile

0

No conozco ningún proyecto existente que haga lo que usted desea, pero no sería tan difícil implementar el ejemplo que usted dio usando lambdas.

Aquí hay otro [no probado/sin compilar/posiblemente defectuosa] idea de utilizar delegados anónimos:

public override string ToString() { 
    return this.ToString(x => { 
     x.Append(t => t.Id); 
     x.Append(t => t.Name); 
    }); 
} 

Este ToString() sobrecarga se escribiría como un método de extensión, por lo que obtener una referencia al objeto de origen, y aceptaría un Action<T> donde [T] es el tipo de objeto fuente. El método ToString() crearía un generador de cadenas o un objeto interno de alguna clase, ejecutaría el método anónimo pasado por la persona que llama y luego ajustaría el resultado en cualquier texto de apertura/cierre que sea necesario.

Para ser claros, en realidad no he intentado esto. Creo que es un poco más flexible que el ejemplo basado en lambda en la pregunta original.

3

Puede que no sea exactamente lo que buscas, ya que no es gratis, pero Resharper hará esto. Es un plugin fantástico para visual studio que hace mucho más que generar ToString. Pero hará eso para. coloque el cursor dentro de su clase, presione alt + insert y elija miembros formateados.

+0

+1 por buen truco de Resharper! – IAdapter

3

La pregunta original que se trate C# 3.5, pero desde entonces he actualizado a C# 4.

pensé que me gustaría compartir mi nueva versión aquí en caso de que sea de beneficio para los demás. Tiene todas las características mencionadas en este hilo y compila en tiempo de ejecución un método Stringify rápido.

Consíguelo aquí: ToStringBuilder

+0

Hola chillitom, tu ToStringBuilder parece bastante impresionante, pero parece que no maneja listas genéricas, como List , simplemente llama a ToString() en la lista sin enumerar, así que solo obtienes el nombre completo de la lista en lugar de los contenidos . Traté de mejorarlo para manejar listas, pero no pude entender usando genéricos con linq Expressions. ¿Alguna vez lo mejoraron para manejar Listas genéricas? ¡Gracias! – matao

+0

lo siento, no lo hice, pero aceptaría una solicitud de extracción. La API de reflexión le permite tomar tipos genéricos y crear tipos reificados, p. typeof (List <>). MakeGenericType (typeof (int)) === typeof (List ) – chillitom

+0

ok, estoy intentando resolverlo, cuando lo haga te enviaré una solicitud. ¡aclamaciones! – matao

0

ObjectPrinter lo hará por usted con una serie de características personalizables. La documentación aún es un poco difícil, pero llevamos años utilizándola en producción con excelentes resultados.

Cuestiones relacionadas