2014-11-26 3 views
1

У меня есть класс с именем Myclass с отключением ToString(), как это:Override 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.

+3

Вы можете использовать отражение, но я постараюсь избежать его. –

+0

Возможно, вам стоит пересмотреть идею. Зачем вам нужно отображать все свойства внутри 'ToString'? –

+0

Для этого вы можете использовать XmlSerializer; бежать, чтобы работать сейчас, но сегодня вечером что-то придумает для демонстрации. – JohnLBevan

ответ

2

Нет, вы не можете сделать это по вашим требованиям, кроме как кодировать каждую функцию вручную. Было бы легко с отражением, но

Метод GetFields не возвращает поля в определенном порядке, например, в алфавитном порядке или порядке декларации. Ваш код не должен зависеть от порядка, в котором возвращаются поля, поскольку этот порядок варьируется.

Таким образом, нет возможности фактически получить заказ декларации. Вы можете попробовать в алфавитном порядке, заказывая их самостоятельно.

2
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 и перегрузку GetValue из .NET 4.5 (Visual Studio 2012).

+0

Это действительно очень хорошее и рабочее решение. –

0

.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 по своему усмотрению лучше подходит для вашего основного требования; предполагая, что вам нужен надежный способ представления данных вашего объекта?
Смежные вопросы