[英]Override ToString function of class
我有一个名为Myclass
的类,它具有ToString()
的重写,如下所示:
class Field
{
}
class MyClass
{
Field propretie1
Field propretie2
.
.
.
Field propretie15
public override string ToString()
{
StringBuilder temp = new StringBuilder();
temp.Append(propretie1.ToString())
temp.Append("|");
temp.Append(propretie2.ToString())
temp.Append("|");
.
.
temp.Append(propretie15.ToString())
return temp.ToString();
}
}
我想知道是否有一种更好的方法可以用声明顺序来遍历Myclass
所有属性,以实现ToString
函数。
不,除了手动编码每个功能外,没有其他方法可以按照您的要求进行操作。 用反射会很容易,但是
GetFields方法不按特定顺序(例如字母顺序或声明顺序)返回字段。 您的代码不得依赖于字段返回的顺序,因为该顺序会有所不同。
因此,实际上无法获得声明的顺序。 您可以通过自己排序来尝试按字母顺序排序。
var allProps = typeof(MyClass).GetProperties(); // or GetFields() if they are fields
Array.Sort(allProps, (x, y) => x.Name.CompareTo(y.Name));
return string.Join("|", allProps.Select(x => x.GetValue(this)));
这将使用Linq Select
和.NET 4.5(Visual Studio 2012)的GetValue
的重载。
.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属性可以做到这一点,以便序列化程序知道您要输出这些属性,然后允许隐式转换为字符串,因此序列化程序不会出错。 奇怪的是,您还需要实现从字符串的隐式转换(我想是因为序列化程序也可以反序列化); 但这不是必须的。 很hacky。
另一种方法是使用[Serializable]
属性使您的子类型可序列[Serializable]
,将[XmlIgnore]
放在任何公共属性上,然后使用调用ToString函数的get方法和伪set方法创建属性(同样可以欺骗序列化程序) 。 不太好,但是可以。
工作实例
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();
}
}
}
另类
[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; }
注意:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.