¿Existe un equivalente a ToStringBuilder de Java para C#?¿Qué características tendría una buena versión de C#?
-
19-09-2019 - |
Pregunta
En el mundo Java tenemos Apache Commons' ParaStringBuilder para ayudar con la creación de implementaciones de toString().
¿Alguien conoce una implementación gratuita decente para C#?¿Hay mejores alternativas que no conozco?
Si no existe una implementación gratuita, supongo que esta pregunta se convierte más en una cuestión de "¿Qué haría un buen ToStringBuilder en C# 3?"
La parte superior de mi cabeza:
Podría ofrecer tanto reflexión como creación manual de cadenas ToString.
Sería realmente genial si pudiera utilizar árboles de expresión.
Algo como esto..
public override string ToString()
{
return new ToStringBuilder<Foo>(this)
.Append(t => t.Id)
.Append(t => t.Name)
.ToString();
}
Que devolvería:
"Foo{Id: 1, Name: AName}"
- Podría usar System.Reflection.Emit para precompilar un delegado ToString.
¿Alguna otra idea?
ACTUALIZAR
Solo para aclarar, ToStringBuilder es una criatura diferente a StringBuilder.Estoy buscando algo similar a la funcionalidad de ToStringBuilder de Apache Common, tiene características como formato de varias líneas, diferentes estilos y creación de ToString base de reflexión.Gracias.
ACTUALIZACIÓN 2
He construido el mío propio.Ver aquí.
Solución
Editar : OK, 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:
Cosa {Id: 10, nombre: "Bob"}
Otros consejos
La pregunta inicial se refería a C # 3.5, pero desde entonces he aumentado a C # 4.
Yo pensé en 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 a un método stringify rápido.
Consíguelo aquí: ToStringBuilder
Puede que no sea exactamente lo que está después, ya que no es libre, pero ReSharper lo hará. Es un fantástico plugin para Visual Studio que hace mucho más que generar ToString. Pero va a hacer eso a. coloque el cursor dentro de su clase, presiona alt + Insertar y seleccione formatear miembros.
Tenga en cuenta que tendrá que proporcionar una pequeña plantilla de sí 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í.
Usted será capaz de crear su propia solución ordenada con el espacio de nombres System.Reflection
en .NET
Saludos
Vea este proyecto ...
ObjectPrinter va a hacer esto para usted con una serie de características personalizables. documentación está siendo un poco duro, pero hemos estado utilizando en la producción durante años con grandes resultados.
Creo que estás en algo con el uso de expresiones. Leí este artículo simplemente la otra noche: Obtener información sobre objetos, tipos y Miembros con árboles de expresión
apuesto a que usted podría combinar estas técnicas con el código que Dan publicado en este hilo para conseguir lo que está después.
No conozco ningún proyecto existente que haga lo que usted quiere, pero no sería tan difícil implementar el ejemplo que dio usando lambdas.
Aquí hay otra idea [no probada/no compilada/posiblemente defectuosa] que utiliza delegados anónimos:
public override string ToString() {
return this.ToString(x => {
x.Append(t => t.Id);
x.Append(t => t.Name);
});
}
Este ToString()
La sobrecarga se escribiría como un método de extensión, por lo que se obtiene una referencia al objeto fuente y se aceptaría un Action<T>
donde [T] es el tipo de objeto fuente.El método ToString() luego crearía un generador de cadenas u objeto interno de algún tipo, ejecutaría el método anónimo pasado por la persona que llama y luego envolvería el resultado en cualquier texto de apertura/cierre que sea necesario.
Para ser claro, en realidad no he intentó este.Simplemente creo que es un poco más flexible que el ejemplo basado en lambda de la pregunta original.