.Net предлагает объект XmlSerializer, предназначенный для предоставления вам вашего объекта. Вы можете воспользоваться этим, просто захватом текстовых узлов и присоединиться к ним:
public override string ToString()
{
return this.Stringify(); //calls reusable code to "stringify" any object
}
//converts an object's properties to a string of pipe delimited values
public static string Stringify<T>(this T obj)
{
var xs = new XmlSerializer(obj.GetType());
var doc = new XDocument();
using (var writer = doc.CreateWriter())
{
xs.Serialize(writer, obj);
}
var s = from text in doc.XPathSelectElements("//*[./text()]") select text.Value;
return string.Join("|", s);
}
Вызов ToString на свойствах, которые являются сложными классами более сложными ... сделать это с помощью атрибута XmlElement на тех свойствах, так сериализатор знает, что вы хотите вывести эти свойства, а затем разрешить неявное преобразование в строку, чтобы сериализатор не выполнял ошибку. Странно, что вам также необходимо реализовать неявное преобразование из строки (я думаю, потому что сериализатор также имеет возможность десериализовать); но это не должно работать. Очень хаки.
Альтернативные, чтобы сделать ваш тип ребенка сериализацию с помощью атрибута [Serializable]
, положить [XmlIgnore]
на каких свойствах, а затем создать свойство с методом GET, призывающей к функции ToString, и методом фиктивного набора (опять-таки обмануть сериалайзер) , Не здорово, но это работает.
Рабочий пример
using System;
using System.Linq;
using System.Xml.Linq;
using System.Xml.Serialization;
using System.Xml.XPath;
namespace StackOverflow
{
public static class ObjectStringer
{
public static string Stringify<T>(this T obj)
{
var xs = new XmlSerializer(obj.GetType());
var doc = new XDocument();
using (var writer = doc.CreateWriter())
{
xs.Serialize(writer, obj);
}
var s = from text in doc.XPathSelectElements("//*[./text()]") select text.Value;
return string.Join("|", s);
}
}
public class Field
{
static int x = 0;
int y;
public Field()
{
y = ++x;
}
public override string ToString()
{
return y.ToString();
}
public static implicit operator String(Field f)
{
return f==null?null:f.ToString();
}
public static implicit operator Field(String s)
{
return s ?? "nasty hack to make serializer work";
}
}
public class Demo
{
public string P1 { get; set; }
public string X { get; set; } //something to show if we're pulling back results in order defined here, or if the system just goes alphabetically
public string P2 { get; set; }
public int P3 { get; set; }
public DateTime P4 { get; set; }
public Demo P5 { get; set; }
[XmlElement(typeof(String))]
public Field P6 { get; set; }
[XmlElement(typeof(String))]
public Field P7 { get; set; }
public override string ToString()
{
return this.Stringify();
}
}
public class Program
{
public static void Main(string[] args)
{
Demo d = new Demo() { P1 = "test1", X = "expert mode", P2 = "test2", P3 = 3, P4 = DateTime.UtcNow, P5 = new Demo() { P1 = "baby", P2 = "ooh" },P6=new Field(),P7=new Field() };
//d.P5 = d; //this solution's not perfect - e.g. attempt to serialize a circular loop in the object's graph
Console.WriteLine(d.ToString());
Console.WriteLine("done");
Console.ReadKey();
}
}
}
Alternative
[Serializable]
public class Field
{
static int x = 0;
int y;
public string DummyToString { get { return this.ToString(); } set { /*serializer hack*/ } }
[XmlIgnore]
public string DontShowMe { get; set; }
public Field()
{
y = ++x;
DontShowMe = "you shouldn't see this";
}
public override string ToString()
{
return string.Format("string me on #{0}", y);
}
}
//Demo's Field properties no longer require XmlElement attributes; i.e.:
public Field P6 { get; set; }
public Field P7 { get; set; }
NB:
- Если у вас есть дочерние элементы, которые являются сложными типами (например, P5 я n приведенный выше пример), как вы хотите, чтобы они обрабатывались? Если их свойства также ограничены контуром (в каком случае, как вы знаете, какие свойства относятся к каким объектам)?
- Как обрабатывать нулевые значения - то же самое, что и пробелы (т. Е. Две трубы без ничего между ними) или вообще не выводятся?
- Было бы лучше вернуть имена свойств, а также значения - чтобы вы не зависели от того, какой заказ/ваш результат более надежны для будущих изменений в определении класса?
- Возможно, XMLSerializer по своему усмотрению лучше подходит для вашего основного требования; предполагая, что вам нужен надежный способ представления данных вашего объекта?
Вы можете использовать отражение, но я постараюсь избежать его. –
Возможно, вам стоит пересмотреть идею. Зачем вам нужно отображать все свойства внутри 'ToString'? –
Для этого вы можете использовать XmlSerializer; бежать, чтобы работать сейчас, но сегодня вечером что-то придумает для демонстрации. – JohnLBevan