Existe um equivalente para ToStringBuilder de Java para C #? O que seria uma boa característica versão C #?
-
19-09-2019 - |
Pergunta
No mundo Java temos Apache Commons' ToStringBuilder para ajuda com a criação de toString () implementações.
Alguém sabe de uma implementação livre decente para C #? Existem alternativas melhores eu não sei sobre?
Se nenhuma implementação livre existe do que eu acho que essa questão torna-se mais de uma questão de "O que faria um bom ToStringBuilder em C # 3?"
Em cima da minha cabeça:
-
Ele poderia oferecer tanto a reflexão e criação de corda ToString manual.
-
Seria muito legal se ele poderia fazer uso de árvores de expressão.
Algo como isso ..
public override string ToString()
{
return new ToStringBuilder<Foo>(this)
.Append(t => t.Id)
.Append(t => t.Name)
.ToString();
}
que retornaria:
"Foo{Id: 1, Name: AName}"
- Ele poderia usar System.Reflection.Emit pré-compilar um delegado ToString.
Quaisquer outras ideias?
Atualizar
Só para esclarecer ToStringBuilder é uma criatura diferente para StringBuilder .. Eu estou procurando algo semelhante à funcionalidade do ToStringBuilder do Apache comum, ele tem recursos como multi-linha de formatação diferentes estilos e criação ToString base de reflexão. Obrigado.
UPDATE 2
Eu construí a minha própria. Veja aqui .
Solução
Editar : OK, você quer usar a reflexão para que você não tem que digitar os nomes de propriedade. Acho que isso vai te dar o que você está depois:
// 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() + "}";
}
}
Exemplo:
// 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();
}
Eis que o comportamento que você está depois:
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());
}
Output:
Coisa {Id: 10, nome: "Bob"}
Outras dicas
A pergunta original em causa C # 3.5, mas desde então tenho atualizado para C # 4.
Eu pensei que eu iria partilhar a minha nova versão aqui no caso, é para benefício de outros. Ele tem todas as características mencionadas neste segmento e compila em tempo de execução a um método stringify rápido.
Obter aqui: ToStringBuilder
Pode não ser exatamente o que você está depois, uma vez que não é livre, mas ReSharper vai fazer isso. É um plugin fantástico para estúdio visual que faz muito mais do que gerar ToString. Mas ele vai fazer isso. colocar o cursor dentro de sua classe, bateu alt + Inserir e escolha a formatação membros.
Use .NET é StringBuilder .
Note que você terá que fornecer um pouco template si mesmo.
por exemplo:
public StringBuilder ToStringBuilder<T>(T type) where T : IYourInterface
{
StringBuilder sb = new StringBuilder();
sb.append(type.key);
// more appends
return sb;
}
Desde uma maneira meio generic
aqui.
Você vai ser capaz de criar sua própria solução elegante com o namespace System.Reflection
em .NET
Felicidades
Veja este projeto ...
ObjectPrinter vai fazer isso por você com uma série de recursos de personalização. documentação ainda é um pouco difícil, mas temos vindo a usá-lo em produção por anos com grandes resultados.
Eu acho que você é sobre a algo com o uso de expressões. Eu li este artigo apenas a outra noite: Obtendo informações sobre objetos, tipos e membros com árvores de expressão
Eu aposto que você poderia combinar essas técnicas com o código que Dan postou neste tópico para obter o que você está depois.
Eu não sei de quaisquer projectos existentes que iria fazer o que quiser, mas não seria tão difícil de implementar o exemplo que você deu usando lambdas.
Aqui está outro [uncompiled / possivelmente defeituoso não testado /] idéia usando delegados anônimos:
public override string ToString() {
return this.ToString(x => {
x.Append(t => t.Id);
x.Append(t => t.Name);
});
}
Essa sobrecarga ToString()
seria escrito como um método de extensão, de modo a obter uma referência para o objeto de origem, e aceitaria uma Action<T>
onde [T] é o tipo de objeto de origem. O método ToString (), então, nova-se um construtor de string ou objeto interno de algum tipo, executar o método anônimo passado do autor da chamada, e em seguida, enrole o resultado em qualquer abertura / fechamento de texto que é necessário.
Para ser claro, eu não tenho realmente tentou isso. Eu só acho que é um pouco mais flexível do que o exemplo à base de lambda na pergunta original.