簡體   English   中英

覆蓋類的ToString函數

[英]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; }

注意:

  • 如果您有復雜類型的子項(例如,上例中的P5),則如何處理它們? 它們的屬性也應該用管道定界嗎(在這種情況下,您如何知道哪些屬性與哪些對象有關)?
  • 空值應該如何處理-與空白相同(即兩個管道之間沒有任何東西),或者根本不輸出?
  • 返回屬性名稱和值會更好-這樣您就不必依賴順序了/輸出對類定義的將來更改更可靠了嗎?
  • 也許XMLSerializer本身更適合您的基本需求; 假設您想要一種強大的方式來表示對象的數據?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM