My project contains a lot of classes, a bunch of which can be described by XML files. Don't worry, it's not the logic or implementation in XML. It's a game, and an example would be that a game tile can be defined in XML, the image file, animation frames, etc.
I'm going to end up having a bunch of functions that look like this:
public static Foo FromXml(ref XmlTextReader reader) { ... }
The question is this: should these functions be contained in their own matching class, for example the one above would be Foo.FromXml. Or, should I make a separate class for reading things from files? There seem to be two general guidelines competing here:
A class should to know everything about one thing - itself.
A class should only have one reason to change.
First of all, I don't really understand the second one, because "reason" is quite vague. The first guideline suggests put each reader in the related class. The second says to make one class dedicated to reading xml files. But the pros and cons are debatable. On the one hand, each class could contain its own reader, so there aren't a dozen classes referenced. On the other hand, every class would have to include System.Xml, and if I change my xml format, things could change in multiple files (but I don't think that's too bad).
I know the most important rule is "use your brain" and there is no such thing as a "correct" solution, only a good and working one. So what do you think would be more readable, or better yet, maintainable?
edit: to clarify, the classes can be totally unrelated. Since it's a game, one may be the sprite animation class, one may define enemy behavior, one might define the map layout or properties. So inheritance has nothing to do with this.
Are the FromXml(...) functions identical? Assuming they are I would be putting it in a common library area, because it will make maintaining them a lot easier as there will be no code duplication. The code should still be neat too
SomeObject o = (SomeObject)Foo.FromXml(reader);
EDIT: Or, possibly, make some base abstract class which just has the FromXml / ToXml functions, then have all classes that want to use those functions inherit from the abstract class.
having a static base class method for all inheriting classes & maintaining proper polymorphism is difficult. You could however remove the static-ness of the method, and have an InitializeFromXml method which would essentially allow you to populate your class from the xml. Though I typically don't care for public Initialize methods, this tends to be better for polymorphism.
here's an example. it's a bit much for a small object like this (and I rarely ever actually use xml serialization, but would load it into an xml document and pull out what I need for deserialization assignments), but when things scale, are inherited, and generally more complex, it allows you to reuse quite a bit more:
public class CustomObject {
public string AValue { get; set; }
public bool BValue { get; set; }
protected IXmlConfiguration Config = new CustomObjectConfig( );
public virtual string ToXml( ) {
return Config.ToXml( this );
}
public virtual void InitializeFromXml( string xml ) {
Config.FromXml( xml );
AValue = ((CustomObjectConfig)Config).A;
BValue = ((CustomObjectConfig)Config).B;
}
}
public interface IXmlConfiguration {
void FromXml( string xml );
string ToXml( object instance );
}
[XmlRoot( "CustomObject" )]
public class CustomObjectConfig : IXmlConfiguration {
[XmlElement( "AValue" )]
public string A { get; set; }
[XmlAttribute( "bvalue" )]
public bool B { get; set; }
public void FromXml( string xml ) {
byte[] bytes = Encoding.UTF8.GetBytes( xml );
using ( MemoryStream ms = new MemoryStream( bytes ) ) {
XmlSerializer xs = new XmlSerializer( typeof( CustomObjectConfig ) );
CustomObjectConfig cfg = (CustomObjectConfig)xs.Deserialize( ms );
A = cfg.A;
B = cfg.B;
}
}
public string ToXml( object instance ) {
string xml = null;
if ( instance is CustomObject ) {
CustomObject val = (CustomObject)instance;
A = val.AValue;
B = val.BValue;
using ( MemoryStream ms = new MemoryStream( ) ) {
XmlSerializer xs = new XmlSerializer( typeof( CustomObjectConfig ) );
xs.Serialize( ms, this );
ms.Seek( 0, 0 );
byte[] bytes = ms.ToArray( );
xml = Encoding.UTF8.GetString( bytes );
}
}
return xml;
}
}
The reason I'd favor this approach rather than creating xml serializable objects are because
xml serialization typically requires
you structure your class one way,
and you will typically then use that
class another way.
it's a bit easier than having huge
stacks of xml include attributes
(may be called something different)
everywhere which would allow the
polymorphic serialization of derived
types.
Related
I'm using XmlSerializer. A big class instance is being serialized, and that big one aggregates (I'd say pretty much owns) smaller classes with some inheritance involved. It appears that in base classes, some properties are crucial and are used to mirror their state when being serialized. But for some of their subclasses those properties should be suppressed, because other, more readable ones, were added.
Here's an example (not real code sample):
class Base
{
public int x { get; set; }
// ...other stuff...
}
class Derived1 : Base
{
// just some added functions
// it's perfectly fine serializing base.x
// ...other stuff...
}
class Derived2 : Base
{
public int y { get; set; } // will in the end be populating this.y
// and base.x, but is more readable and has more sense in XML
// ...other stuff...
}
class BigClass
{
public List<Derived1> List1 { get { return m_List1; } }
private List<Derived1> m_List1 = new List<Derived1>();
public List<Derived2> List2 { get { return m_List2; } }
private List<Derived2> m_List2 = new List<Derived2>();
// ...other stuff...
}
I've read this for the topic of using XmlAttributeOverrides. Apparently, it works for situations like XmlSerializer s = new XmlSerializer(typeof(Derived2), overrides). However, when I try to use it with BigClass:
XmlAttributeOverrides overrides = new XmlAttributeOverrides();
XmlAttributes ignore = new XmlAttributes { XmlIgnore = true };
overrides.Add(typeof(Derived2), "x", ignore);
XmlSerializer serializer = new XmlSerializer(typeof(BigClass), overrides);
// and, finally, save it
using (TextWriter tw = new StreamWriter("output.xml"))
{
serializer.Serialize(tw, SomeBigClassInstance);
}
the output still contains the x property for both types. The Lists contain them by reference to the appropriate subclass, so it's not like XmlSerializer cannot see their actual class. Despite the overrides, the sample xml output would look like
<?xml version="1.0" encoding="utf-8"?>
<BigClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<List1>
<Derived1>
<x>1</x>
<!-- other stuff -->
</Derived1>
</List1>
<List2>
<Derived2>
<x>2</x> <!-- unwanted guy -->
<y>20</y>
<!-- other stuff -->
</Derived2>
</List2>
<!-- other stuff -->
</BigClass>
So the question is: what am I doing wrong here? Does this method of suppressing unwanted properties only work when serializer is deliberately applied to the node of this class only?
Note. The savings in my real case are bigger than just one line. There are more properties to be hidden like this, and lists can contain decently large amount of items. The concern is readability and to some extent, manual modifiability of the resulting xml-files. Apparently, recalculating x properties or deleting them by hand is tiresome enough to attempt such endeavor.
Update 1. Trying to add code like
overrides.Add(typeof(List<Derived2>), "x", ignore);
doesn't seem to fix it. There are actually more nodes from BigClass down to Derived1/2 in the aggregation hierarchy. And adding them all from Derived2 up to the root didn't help. So I'm assuming this proposal won't fix it even in this simplified case. (Update 2. It won't).
(Disclaimer. Some people might say that serialized fields are like public interface of the class in question, so hiding them in derived classes is kind of a code smell. But I'm not going to address interface implications here, only the way the said goal can achieved.)
There are two features of XmlSerializer that allow to exclude some properties from the output file:
<field>Specified pattern (AKA the old way), e.g. like in here: How to make a value type nullable with .NET XmlSerializer?
ShouldSerialize<field>() pattern, e.g. like here: Xml serialization - Hide null values
Both have some pros and cons in the removing redundant fields down the inheritance tree. Let's see:
<field>Specified pattern. Usage:
public class Example
{
public int x { get; set; }
[XmlIgnore]
public bool xSpecified;
public Example()
{
xSpecified = <set your value for this class>;
}
}
Pros:
Can be set in other classes in case if the logic demands it
Cons:
Breaks encapsulation of the class in question
Contributes to object's size in memory, one boolean per object per property
You have to remember to set it to appropiate value, e.g. in constructor
ShouldSerialize<field>() pattern. Usage:
public class Example
{
public int x { get; set; }
public virtual bool ShouldSerializex()
{
return <your logic expression here>;
}
}
Pros:
Keeps the encapsulation of the class, allows the logic to be contained in it
No additional memory per property
More flexible overall
Cons:
In this case, having to make it virtual so it would work with derived classes as well, so possibly additional memory for vtable pointer in each object
For the particular issue of mine I utilized both approaches in different places. Self-sufficient classes with several properties needing to be hidden get more advantage out of #2, especially if the project has lists upon lists of lots of their instances. Small classes used to be "brick stones" for composing larger ones might be "dumb" enough to be ignorant whether to serialize some stuff or not, which makes #1 a possible option.
Suppose you have 2 classes like so:
public class ClassA {
public int X { get; set; }
public int Y { get; set; }
public int Other { get; set; }
}
public class ClassB {
public int X { get; set; }
public int Y { get; set; }
public int Nope { get; set; }
}
Now imagine you have an instance of each class and you want to copy the values from a into b. Is there something like MemberwiseClone that would copy the values where the property names match (and of course is fault tolerant -- one has a get, and the other a set, etc.)?
var a = new ClassA(); var b = new classB();
a.CopyTo(b); // ??
Something like this is pretty easy in a language like JavaScript.
I'm guessing the answer is no, but maybe there is a simple alternative too. I have written a reflection library to do this, but if built in to C#/.NET at a lower level would probably be more efficient (and why re-invent the wheel).
There's nothing in the framework for object-object mapping but there's a very popular library out there that does this: AutoMapper.
AutoMapper is a simple little library built to solve a deceptively
complex problem - getting rid of code that mapped one object to
another. This type of code is rather dreary and boring to write, so
why not invent a tool to do it for us?
By the way, just for learning, here's a simple way you can implement what you want. I haven't tested it thoroughly, and it's nowhere as robust / flexible / performant as AutoMapper, but hopefully there's something to get out of the general idea:
public void CopyTo(this object source, object target)
{
// Argument-checking here...
// Collect compatible properties and source values
var tuples = from sourceProperty in source.GetType().GetProperties()
join targetProperty in target.GetType().GetProperties()
on sourceProperty.Name
equals targetProperty.Name
// Exclude indexers
where !sourceProperty.GetIndexParameters().Any()
&& !targetProperty.GetIndexParameters().Any()
// Must be able to read from source and write to target.
where sourceProperty.CanRead && targetProperty.CanWrite
// Property types must be compatible.
where targetProperty.PropertyType
.IsAssignableFrom(sourceProperty.PropertyType)
select new
{
Value = sourceProperty.GetValue(source, null),
Property = targetProperty
};
// Copy values over to target.
foreach (var valuePropertyTuple in tuples)
{
valuePropertyTuple.Property
.SetValue(target, valuePropertyTuple.Value, null);
}
}
There's nothing like this in .NET that I'm aware of, but one library that is able to do this (and much more) is AutoMapper. For your case, something like:
_mapper.Map<A, B> (a, b);
As far as I know this does not exist. The way I have been doing it is by:
public static T DeepCopy(T oldclass)
{
using (MemoryStream stream = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, oldclass);
ms.Position = 0;
return (T)formatter.Deserialize(stream);
}
}
See the interface System.ICloneable, and the method System.Object.MemberwiseClone(). As noted in the MSDN docs,
The MemberwiseClone method creates a shallow copy by creating a new object, and then copying the nonstatic fields of the current object to the new object. If a field is a value type, a bit-by-bit copy of the field is performed. If a field is a reference type, the reference is copied but the referred object is not; therefore, the original object and its clone refer to the same object.
I'm creating an application that basically downloads and uploads files from various types of locations. I asked some advice on here and I was told that I should take an Object Oriented Approach with something like this, but this is my first real usage of OOP so I'm having a hard time understanding how to carry out what I want. Here is what I have so far:
public class FileListClass
{
public string sourcetype;
public string source;
public string destination;
public string destinationtype;
public bool deleteSource;
}
How do I actually enter a file into here in my main method? When I create a new list based on this class, .Add on the list requires an item of 'FileListClass' type - how do I create this?
you can do some thing lik ethis
FileListClass oFileListClass = new FileListClass();
oFileListClass.sourcetype="";
oFileListClass.source="";
oFileListClass.destination="";
oFileListClass.destinationtype="";
oFileListClass.deleteSource=false;
this will create one object, and you can create as many as possible like this with diffrent values.
if you wana keep this in List then create list of type FileListClass like
List<FileListClass > oListFileListClass = new List<FileListClass >();
then add all of your objects in this like
oListFileListClass.Add(oFileListClass);
Short answer:
var yourList = new System.Collections.Generic.List<FileListClass>();
yourList.Add(new FileListClass
{
sourcetype = "...",
source = "...",
...
});
Longer answer:
The above should work, but do take note that your class is not particularly well-designed (IMHO). It's more of a simple data record/container than a class that's "true" to OO principles. This may be just fine, depending on your requirements.
It's uncommon to expose fields directly in C#. Usually, only properties are exposed: public string SourceType { get; set; }
sourcetype and destinationtype are slightly suspect -- this might be a case where subclassing (class inheritance) might be suitable later on. Even without that, and without me knowing what exactly you're going to store in those two fields, have you considered using enums for them instead of plain strings?
In C#, it's common practice to name public members with CamelCase capitalization.
First, it's a bettere approach to define Enums for your constant types, something like
public enum SourceTypes
{
Network = 0,
WAN =1,
}
ecc. ecc.
then modify your FileLystClass as follows
public class FileListClass
{
public SouceTypes sourceType;
...
public DestinationTypes destinationType;
...
}
then, to answer your question.
You have defined a a class(a type) called FileListClass.
To use it, just create as many instance you want, populating the fields of the objects accordingly to your sources
public void CreateFileListList()
{
for (int i = 0; i <100; i++)
{
FileListClass flo = new FileListClass
flo.sourceType = SourceTypes.WAN;
flo.deletesource = true;
[...]
myList.add(flo);
}
}
I would suggest laying out the basic actions that are needed in your program:
DownloadFrom(String loc);
UploadFrom(String loc);
Then you can build lower levels of your app:
DownloadFrom(String loc);
HTTPConnect();
FTPConnect();
etc..
UploadFrom(String loc);
HTTPConnect();
FTPConnect();
etc..
At this point you can already have a feeling of the structure of your program, you can in fact create classes around your different actions:
class Connect {
HTTPConnect();
FTPConnect();
}
class Download : Connect{
DownloadFrom(String loc);
}
class Upload : Connect{
UploadFrom(String loc);
}
As you can see this is a first approach to OOP. There are many advantages to use a structure of Objects around your program but It would be too hard of an explanation. Try reading Google about it: Advantages of OOP.
I'm using a 3rd party's set of webservices, and I've hit a small snag. Before I manually make a method copying each property from the source to the destination, I thought I'd ask here for a better solution.
I've got 2 objects, one of type Customer.CustomerParty and one of type Appointment.CustomerParty. The CustomerParty objects are actually property and sub-oject exactly the same. But I can't cast from 1 to the other.
So, I need to find a certain person from the webservice. I can do that by calling Customer.FindCustomer(customerID) and it returns a Customer.CustomerParty object.
I need to take that person that I found and then use them a few lines down in a "CreateAppointment" request. Appointment.CreateAppointment takes an appointment object, and the appointment object contains a CustomerParty object.
However, the CustomerParty object it wants is really Appointment.CustomerParty. I've got a Customer.CustomerParty.
See what I mean? Any suggestions?
Why don't you use AutoMapper? Then you can do:
TheirCustomerPartyClass source = WebService.ItsPartyTime();
YourCustomerPartyClass converted =
Mapper.Map<TheirCustomerPartyClass, YourCustomerPartyClass>(source);
TheirCustomerPartyClass original =
Mapper.Map<YourCustomerPartyClass, TheirCustomerPartyClass>(converted);
As long as the properties are identical, you can create a really simple map like this:
Mapper.CreateMap<TheirCustomerPartyClass, YourCustomerPartyClass>();
Mapper.CreateMap<YourCustomerPartyClass, TheirCustomerPartyClass>();
This scenario is common when writing domain patterns. You essentially need to write a domain translator between the two objects. You can do this several ways, but I recommend having an overridden constructor (or a static method) in the target type that takes the service type and performs the mapping. Since they are two CLR types, you cannot directly cast from one to the other. You need to copy member-by-member.
public class ClientType
{
public string FieldOne { get; set; }
public string FieldTwo { get; set; }
public ClientType()
{
}
public ClientType( ServiceType serviceType )
{
this.FieldOne = serviceType.FieldOne;
this.FieldTwo = serviceType.FieldTwo;
}
}
Or
public static class DomainTranslator
{
public static ServiceType Translate( ClientType type )
{
return new ServiceType { FieldOne = type.FieldOne, FieldTwo = type.FieldTwo };
}
}
I'm using a 3rd party's set of
webservices...
Assuming you can't modify the classes, I'm not aware of any way you can change the casting behavior. At least, no way that isn't far, far more complicated than just writing a CustomerToAppointmentPartyTranslator() mapping function... :)
Assuming you're on a recent version of C# (3.5, I believe?), this might be a good candidate for an extension method.
Have you looked at adding a conversion operator to one of the domain classes to define an explicit cast. See the msdn documentation here.
Enjoy!
A simple and very fast way of mapping the types is using the PropertyCopy<TTarget>.CopyFrom<TSource>(TSource source)
method from the MiscUtil library as described here:
using MiscUtil.Reflection;
class A
{
public int Foo { get; set; }
}
class B
{
public int Foo { get; set; }
}
class Program
{
static void Main()
{
A a = new A();
a.Foo = 17;
B b = PropertyCopy<B>.CopyFrom(a);
bool success = b.Foo == 17; // success is true;
}
}
Two classes with exactly the same signature, in two different namespaces, are two different classes. You will not be able to implicitly convert between them if they do not explicitly state how they can be converted from one to the other using implicit or explicit operators.
There are some things you may be able to do with serialization. WCF DataContract classes on one side do not have to be the exact same type as the DataContract on the other side; they just have to have the same signature and be decorated identically. If this is true for your two objects, you can use a DataContractSerializer to "convert" the types through their DataContract decoration.
If you have control over the implementation of one class or the other, you can also define an implicit or explicit operator that will define how the other class can be converted to yours. This will probably simply return a new reference of a deep copy of the other object in your type. Because this is the case, I would define it as explicit, to make sure the conversion is only performed when you NEED it (it will be used in cases when you explicitly cast, such as myAppCustomer = (Appointment.CustomerParty)myCustCustomer;).
Even if you don't control either class, you can write an extension method, or a third class, that will perform this conversion.
I noticed the XmlSerializer is more forgiving to adding new members, removing existing ones, etc to the serialized types.
When I did this with the BinaryFormatter, and tried to deserialize the old data, it threw an exception.
What other alternatives are there for forgiving options, i.e. one that doesn't throw an exception just uses default values, skips them, etc?
Are protocol buffers forgiving in this regard?
You mention binary, and indeed BinaryFormatter is very brittle here. The problem is that BinaryFormatter is type and field based. Instead, you want a contract-based serializer, such as XmlSerialzier, DataContractSerializer (3.0), etc.
Or for binary, protobuf-net is a C# implementation of Google's "protocol buffers" wire format, but re-implemented along .NET lines; (note: I'm the author...).
It is (like the others) data-contract based, but instead of <CustomerName>asdasd</CustomerName> etc, it uses numeric tags to identify things instead; so:
[ProtoContract]
public class Customer {
[ProtoMember(1)]
public string Name {get;set;}
// ...
}
As you add more members you give them new unique numbers; this keeps it extensible without relying on any names etc. Plus it is very fast ;-p As with XmlSerializer, it will ignore things it doesn't expect (or it can store them for safe round-trip of unexpected data), and supports the same default things. You can even use your existing xml attributes:
[XmlType]
public class Customer {
[XmlElement(Order=1)]
public string Name {get;set;}
// ...
}
I could talk about this subject all day, so I'd better shut up before [too late].
You could inherit your class from ISerializable and define a custom GetObjectData. I haven't tested this, but such a class might be deserializable from a binary format, even if changes have since been made to the class.
EDIT
I just confirmed that this works. You can use code like the example below to explicitly define how an object is serialized and deserialized. It would then be up to you to make these methods work with older versions of your class. I tested this by serializing an instance of Cereal to a binary file, then making changes to the class and reading the file back in for deserialization.
[Serializable]
private class Cereal : ISerializable
{
public int Id { get; set; }
public string Name { get; set; }
public Cereal()
{
}
protected Cereal( SerializationInfo info, StreamingContext context)
{
Id = info.GetInt32 ( "Id" );
Name = info.GetString ( "Name" );
}
public void GetObjectData( SerializationInfo info, StreamingContext context )
{
info.AddValue ( "Id", Id );
info.AddValue ( "Name", Name );
}
}
I strongly recommend doing your own serialization so that you have well-defined file formats independent of the language schemes.
I actually find that the binary formatter is the most durable in the long run.
It provides excellent forward compatibility. That is to say, if you upgrade the file to a new version, it will not work with the old deserializer.
I generally create some simple data classes that I want to use for serialization. When i need to change the class, I implement the OnDeserialized / OnDeserializing methods. This allows the data to be upgraded.
The binary formatter does not require that you have a public setter for your properties, which to me is a big problem sometimes.
[Serializable]
public class data
{
private int m_MyInteger;
// New field
private double m_MyDouble;
[OnDeserializing]
internal void OnDeserializing(StreamingContext context)
{
// some good default value
m_MyDouble = 5;
}
public int MyInteger
{
get{ return m_MyInteger; }
set { m_MyInteger = value; }
}
}
I think the following post could help you. I also agree with others who said to write your own serializer. It is way better than generated code from xsd.exe .
See the post below:
Serialization and Deserialization into an XML file, C#
You can also look at the OptionalFieldAttribute for use with SerializableAttribute/NonSerializedAttribute and the BinaryFormatter and SoapFormatter
... version 1
[Serializable]
public class MyClass
{
public string field1;
[NonSerialized]
public string field2;
}
... version 2
[Serializable]
public class MyClass
{
public string field1;
[NonSerialized]
public string field2;
[OptionalField]
public string field3;
}