Override ToString function of class - c#

I have a class named Myclass with an override of ToString() like this:
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();
}
}
I'd like to know if there is a better way to get over all the properties of Myclass with the declaration order to implement the ToString function.

No, there is no way to do this by your requirements other than coding each function manually. It would be easy with reflection, but
The GetFields method does not return fields in a particular order, such as alphabetical or declaration order. Your code must not depend on the order in which fields are returned, because that order varies.
So there is no way to actually get the order of the declaration. You could try alphabetical order by ordering them yourself though.

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)));
This uses Linq Select and an overload of GetValue from .NET 4.5 (Visual Studio 2012).

.Net offers an XmlSerializer object aimed at giving you a representation of your object.
You can take advantage of that, just grabbing text nodes and joining them:
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);
}
Calling ToString on properties which are complex classes is more complex... to do that use the XmlElement attribute on those properties so the serializer knows you want to output these properties, then allow implicit conversion to string so the serializer doesn't error. Weirdly you also need to implement implicit conversion from string too (I guess because the serializer has the ability to deserialize too); but that doesn't have to work. Very hacky.
An alternate is to make your child type serializable using the [Serializable] attribute, put [XmlIgnore] on any public properties, then create a property with a get method calling to ToString function, and a dummy set method (again to trick the serializer). Not great, but it works.
Working Example
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:
If you have child items which are complex types (e.g. P5 in the above example), how do you want them handled? Should their properties also be pipe delimited (in which case how do you know which properties relate to which objects)?
How should null values be handled - same as blanks (i.e. two pipes with nothing between them), or not output at all?
Would it be better to return the property names as well as values - so you're not reliant on the order / your output's more robust to future changes in class definition?
Perhaps the XMLSerializer on its own better suits your underlying requirement; assuming you want a robust way of representing your object's data?

Related

C# foreach loop thru collection of unknown type

I have a generic method that can be called with 2 different object types, TypeA or TypeB. TypeA and TypeB are essentially identical classes except in name only. I am trying to determine how to prevent from having to duplicate the Foreach loop code for each object type. Is this possible ? thanks.
public class TypeA
{
public string Name { get; set; }
public string Department { get; set; }
public string Total { get; set; }
}
public class TypeB
{
public string Name { get; set; }
public string Department { get; set; }
public string Total { get; set; }
}
private CsvExport GenerateExport<T>(IEnumerable<T> scores)
{
CsvExport export = new CsvExport();
List<TypeA> aList = null;
List<TypeB> bList = null;
Type type = scores.GetType();
if (type.FullName.Contains("TypeA"))
{
aList = scores as List<ObjectaModel>;
}
else if (type.FullName.Contains("TypeB"))
{
bList = scores as List<ObjectbModel>;
}
foreach (var dt in aList)
{
export.AddRow();
export["Name"] = dt.Name;
export["Department"] = dt.Department;
export["Total "] = dt.Total;
};
return export;
}
In this particular case I strongly suggest you delegate the hard work to the CsvHelper library which you can also obtain from Nuget and is used like this...
public void ExportToCsv<T>(string filename, ImmutableArray<T> objects)
{
using (var writer = File.CreateText(filename))
{
var csv = new CsvWriter(writer);
csv.WriteRecords(objects);
}
}
The more general answer to your question is that you must either have both classes inherit from a common class or interface or you would have to use reflection to look for an obtain the values of the named properties.
Using a common interface...
public interface IScore
{
int HiScore {get;}
}
public class ScrabbleScore : IScore
{
public int HiScore {get;set;}
}
public class PacManScore : IScore
{
public int HiScore {get;set;}
}
public void Export<T>(IEnumerable<T> scores) where T: IScore
{
foreach(var s in scores)
{
CvsExport["Hi score"]= s.HiScore;
}
}
Using reflection...
var CsvExport = new Dictionary<string,string>();
foreach(var o in scores)
{
//note that checking the type for each object enables you to have heterogenous lists if you want
var objectType= o.GetType();
foreach(var p in objectType.GetProperties())
{
var propertyName = p.Name;
CsvExport[propertyName] = p.GetValue(o).ToString();
}
}
I would treat the reflection solution as the least favoured of the three.

Output to file c#

I am using the Apriori Algorithm to get strong rules. So far I have got them in a list box(program was found online). However now I would like to save the output to a txt file. So far all I have been getting in the .txt file is "AprioriAlgorithm.Rule". It is getting the correct number of rules, thus repeating the "AprioriAlgorithm.Rule for the number of rules. For example, if I have 12 strong rules, I get AprioriAlgoritm.Rule for 12 times in the txt file.
namespace WPFClient
{
[Export(typeof(IResult))]
public partial class Result : Window, IResult
{
public Result()
{
InitializeComponent();
}
public void Show(Output output)
{
FileStream fs = new FileStream("strongrules.txt", FileMode.Create);
StreamWriter sw = new StreamWriter(fs);
this.DataContext = output;
for (int x = 0; x < output.StrongRules.Count; x++)
{
sw.WriteLine(output.StrongRules[x]);
}
this.ShowDialog();
sw.Close();
}
}
}
And this is the output class.
namespace AprioriAlgorithm
{
using System.Collections.Generic;
public class Output
{
#region Public Properties
public IList<Rule> StrongRules { get; set; }
public IList<string> MaximalItemSets { get; set; }
public Dictionary<string, Dictionary<string, double>> ClosedItemSets { get; set; }
public ItemsDictionary FrequentItems { get; set; }
#endregion
}
}
Since you are passing object of type Rule instead of string to the WriteLine method you have to specify what exactly you want to output.
You need to override the ToString() method of your Rule class in order to do that.
public class Rule
{
public string RuleName { get; set; }
public string RuleDescription { get; set; }
public override string ToString()
{
return string.Format("{0}: {1}", RuleName, RuleDescription);
}
}
As documentation says
Writes the text representation of an object by calling the ToString method on that object, followed by a line terminator to the text string or stream.
Another way to do this (other than overriding ToString) is to output the individual properties:
var rule = output.StringRules[x];
sw.WriteLine("{0}: {1}", rule.RuleName, rule.RuleDescription);
Or, using the string interpolation feature of C#:
sw.WriteLine($"{rule.RuleName}: {rule.RuleDescription}");
You'd want to use this if you can't or don't want to override ToString.

Serialize / Deserialize XML Derived From Treenode

I have two classes, "company" derived from Treenode, and "document".
[Serializable]
[XmlRoot("Company")]
public class Company : TreeNode, IXmlSerializable
{
private string _x;
private string _y;
public Company() { }
[XmlElement("X")]
public string X { get; set; }
[XmlElement("Y")]
public string Y { get; set; }
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
if (reader.MoveToContent() == XmlNodeType.Element && reader.LocalName == "Company")
{
x = reader["X"].ToString;
y = reader["Y"].ToString;
}
}
public void WriteXml(XmlWriter writer)
{
writer.WriteElementString("X", this.X.ToString());
writer.WriteElementString("Y", this.Y.ToString());
}
}
public class Document
{
private int _id;
private string _name;
private Company _company;
public Document() { }
[XmlElement("ID")]
public int ID { get; set; }
[XmlElement("Name")]
public string Name { get; set; }
[XmlElement("Company")]
public Company Comp { get; set; }
}
When I try to serialize document, then save to file, its work. But when I deserialize, reader parameter always null. Any solutions ?
This is my code for deserialize. "sr" is variable that hold xml text.
var sr = new StreamReader(ms);
var myStr = sr.ReadToEnd();
XmlSerializer serializer = new XmlSerializer(typeof(List<Document>));
using (TextReader tr = new StringReader(myStr))
{
List<Document> docu = (List<Document>)serializer.Deserialize(tr);
}
I try to implement ISerialization and debug but never fired, and try to overide serialize and deserialize method, and no luck.
I am using .NET Framework 3.5
As explained in this article, implementing IXmlSerializable correctly is in fact quite tricky. Your implementation of ReadXml() appears to violate the requirement that it consume the wrapper element itself as well as all the contents, like so:
public void ReadXml(System.Xml.XmlReader reader)
{
reader.MoveToContent();
// Read attributes
Boolean isEmptyElement = reader.IsEmptyElement; // (1)
reader.ReadStartElement();
if (!isEmptyElement) // (1)
{
// Read Child elements X and Y
// Consume the end of the wrapper element
reader.ReadEndElement();
}
}
Furthermore, reader["X"] returns the value of the XML attribute named "X", as explained in the docs. In your WriteXml() you wrote the values of X and Y as nested XML elements. This explains the NullReferenceException. You need to fix your read and write methods to be consistent.
However, I'd suggest an alternative to implementing IXmlSerializable, which is to introduce a surrogate type for your Company. First, extract all the non-TreeNode properties of Company into an interface:
public interface ICompany
{
string X { get; set; }
string Y { get; set; }
}
public class Company : TreeNode, ICompany
{
public Company() { }
public string X { get; set; }
public string Y { get; set; }
}
This is optional but makes the code clearer. Next, introduce a surrogate POCO that implements the same interface but does not inherit from TreeNode:
public class CompanySurrogate : ICompany
{
public string X { get; set; }
public string Y { get; set; }
public static implicit operator CompanySurrogate(Company company)
{
if (company == null)
return null;
// For more complex types, use AutoMapper
return new CompanySurrogate { X = company.X, Y = company.Y };
}
public static implicit operator Company(CompanySurrogate surrogate)
{
if (surrogate == null)
return null;
// For more complex types, use AutoMapper
return new Company { X = surrogate.X, Y = surrogate.Y };
}
}
Notice that the surrogate can be implicitly converted to your original Company type? Now you can use the surrogate in XML serialization by setting the XmlElementAttribute.Type attribute property to be that of the surrogate:
public class Document
{
public Document() { }
[XmlElement("ID")]
public int ID { get; set; }
[XmlElement("Name")]
public string Name { get; set; }
[XmlElement("Company", Type = typeof(CompanySurrogate))]
public Company Comp { get; set; }
}
This avoids all possibilities of error in implementing IXmlSerializable. Given the following input list:
var list = new List<Document>
{
new Document { Name = "my name", ID = 101, Comp = new Company { X = "foo", Y = "bar", NodeFont = new System.Drawing.Font("Arial", 10) } },
new Document { Name = "2nd name", ID = 222, Comp = new Company { X = "tlon", Y = "ukbar" } },
};
The following XML can will be generated, and can be deserialized successfully:
<ArrayOfDocument xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Document>
<ID>101</ID>
<Name>my name</Name>
<Company>
<X>foo</X>
<Y>bar</Y>
</Company>
</Document>
<Document>
<ID>222</ID>
<Name>2nd name</Name>
<Company>
<X>tlon</X>
<Y>ukbar</Y>
</Company>
</Document>
</ArrayOfDocument>
That being said, I don't really recommend this design. Your UI should present your data model, it should not be your data model. See for instance How does one implement UI independent applications?. Replacing Company with ICompany whenever possible could be a first step to changing your design; you may find it becomes easier to replace your existing architecture with a TreeNode that looks like this:
public class CompanyNode : TreeNode
{
public ICompany Company { get; set; }
}

comparing versions of the same object

What's the best way to compare 2 versions of the same object and return a list of differences (name of property, old value and new value) See object graph below for an example. What if there was a change in the Product name how would I bubble that up into a list of property differences?
static void Main(string[] args)
{
Customer c1 = new Customer();
c1.DBA = "Test1";
c1.LatestOrder.DateOrdered = new DateTime(2011, 7, 12);
c1.LatestOrder.OrderDetails.Product = "Product1";
Customer c2 = new Customer();
c2.DBA = "Test1";
c2.LatestOrder.DateOrdered = new DateTime(2011, 7, 12);
c2.LatestOrder.OrderDetails.Product = "Product2";
}
So the test above shows that everything in the 2 objects are the same except for the product name. Maybe, just as proof of concept, a list showing the property name, old value and new value.
public class Customer
{
public string DBA { get; set; }
public Order LatestOrder { get; set; }
public Customer()
{
LatestOrder = new Order();
}
}
public class Order
{
public int Id { get; set; }
public DateTime DateOrdered { get; set; }
public OrderDetails OrderDetails { get; set; }
public Order()
{
OrderDetails = new OrderDetails();
}
}
public class OrderDetails
{
public String Product { get; set; }
}
}
You could try it using reflection. Something like this:
class Difference
{
private Difference(string propertyPath, object value1, object value2)
{
PropertyPath = propertyPath;
Value1 = value1;
Value2 = value2;
}
public string PropertyPath { get; private set; }
public object Value1 { get; private set; }
public object Value2 { get; private set; }
public Difference Extend(string propertyName)
{
return new Difference(
string.Format("{0}.{1}", propertyName, PropertyPath), Value1, Value2);
}
public override string ToString()
{
return string.Format("{0}: {1}, {2}", PropertyPath, Value1, Value2);
}
public static IEnumerable<Difference> GetDifferences<T>(T value1, T value2)
{
return GetDifferences(typeof(T), value1, value2);
}
// types in this collection are compared directly
// and not recursively using their properties
private static readonly Type[] PrimitiveTypes =
new[] { typeof(int), typeof(string), typeof(DateTime) };
public static IEnumerable<Difference> GetDifferences(
Type type, object obj1, object obj2)
{
foreach (var property in
type.GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
var val1 = property.GetValue(obj1, null);
var val2 = property.GetValue(obj2, null);
if (PrimitiveTypes.Contains(property.PropertyType))
{
if (!val1.Equals(val2))
yield return new Difference(property.Name, val1, val2);
}
else
{
foreach (var difference in
GetDifferences(property.PropertyType, val1, val2))
yield return difference.Extend(property.Name);
}
}
}
}
This recursively walks the object graph and returns something like
LatestOrder.DateOrdered: 12.7.2011 0:00:00, 11.7.2011 0:00:00
LatestOrder.OrderDetails.Product: Product1, Product2
Doing this is quite fragile, though. For example, it could easily cause stack overflow if you have any kind of cyclic relations. (For example, DateTime does, in the form of the Date property, so I had to include it in primitive types.) And if you have some property that depends on other properties, one actual difference may be reported multiple times. (If DateTime wasn't cyclic, this would happen there: two DateTimes that differ in the Seconds property also differ in TotalSeconds, TotalMinutes, etc.)
this may help you get started, essentially if you know obj1 and obj2 are of the same type, you get all of the public properties and compare them one by one... you may want to handle collections differently though (comparing each item in the collection)...
you could then compile all this info in some dictionary or custom object.
foreach (var info in obj1.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
var val1 = info.GetValue(obj1, null);
var val2 = info.GetValue(obj2, null);
// check if val1 == val2
}
You could do something similar to the Comparable class, but with a list of differences instead of an integer. For example
public class ClassName {
...
ArrayList compareTo(ClassName other) {
if (this.attribute.equals(other.attribute)) {
add to list
}
}
}
If the old version and the new version are in the same object instance, maybe you can use a variant of the Memento Pattern (http://en.wikipedia.org/wiki/Memento_pattern).
If you are thinking to create a reusable component, you should think about the use of reflection classes. With reflection you can view all the properties values, even if you don't know all the properties names.

Accessing object properties from string representations

In actionscript an object's property can be accesses in this way:
object["propertyname"]
Is something like this possible in c#, without using reflection?
No, you have to use reflection.
If could at most create an helper extension method like in this example:
using System;
static class Utils {
public static T GetProperty<T>(this object obj, string name) {
var property = obj.GetType().GetProperty(name);
if (null == property || !property.CanRead) {
throw new ArgumentException("Invalid property name");
}
return (T)property.GetGetMethod().Invoke(obj, new object[] { });
}
}
class X {
public string A { get; set; }
public int B { get; set; }
}
class Program {
static void Main(string[] args) {
X x = new X() { A = "test", B = 3 };
string a = x.GetProperty<string>("A");
int b = x.GetProperty<int>("B");
}
}
This is not good, however.
First because you are turning compile-time errors in runtime errors.
Second, the performance hit from reflection is unjustified in this case.
I think that the best advice here is that you should not try to program in C# as if it was ActionScript.
You can define indexer in your class:
public class IndexerTest
{
private Dicionary<string, string> keyValues = new ...
public string this[string key]
{
get { return keyValues[key]; }
set { keyValues[key] = value; }
}
}
And use it like this:
string property = indexerTest["propertyName"];

Categories