Serialize Abstract class with different attribute name - c#

Working on an export flow, I have a few XML elements that represent the same thing, but with a different name. I can't change those names as they're defined by the other software.
I need something like that:
<class1>
<MY_FIELD></MY_FIELD>
</class1>
<class2>
<my_field></my_field>
</class2>
As the treatments that need to be done on both fields are the same, I wanted to create an abstract class that contains it.
Right now, this is what I have:
public abstract class MyAbstract
{
[XmlAttribute("MY_FIELD")]
public MyField {get;set;}
}
[Serializable]
public class Class1 : MyAbstract
{
}
[Serializable]
public class Class2 : MyAbstract
{
}
Is there a way to specify a different XmlAttribute on the final class (class1 and class2) so I can set the attribute on MyField ?
Edit:
I'm trying to use XmlAttributeOverrides, that seems to do what I want, but I can't make it work. I don't know what I am missing.
var myType = typeof(Class1);
var overrides = new XmlAttributeOverrides();
var attrs = new XmlAttributes
{
XmlAttribute = new XmlAttributeAttribute("test")
};
overrides.Add(myType, "MyField",attrs);
and for the serializer
var serializer = new XmlSerializer(myType, overrides);
Edit2:
Finally I end up removing the attribute on my abstract class and add a getter on each class for serialization purpose. It's crappy but I still hope someone can give me a proper option.

Try
public abstract class MyAbstract
{
abstract public MyField {get;set;}
}
[Serializable]
public class Class1 : MyAbstract
{
[XmlAttribute("MY_FIELD")]
public override MyField {get;set;}
}
[Serializable]
public class Class2 : MyAbstract
{
[XmlAttribute("my_field")]
public override MyField {get;set;}
}

Related

C# serialize JSON Object to a class

I am working on Json Obejct deserielize to a class in .net VS2015 on win 7.
public class1
{
[JsonProperty(TypeNameHandling = TypeNameHandling.Objects)]
public Class1 data1;
public Class2 data2;
}
public abstract Class1
{
some functions
}
public subClass1 : Class1
{
public string myData1 { get; set; }
public string myData2 { get; set; }
}
In my code of deserierlizing:
var mo = MyObject as JObject;
ParentMyClass = mo.ToObject<MyClass>();
I know that an abstract class cannot be instantiated.
So, subClass1 (which is one of the implementation of Class1) is serialized.
But, subClass1 is null after deserialized.
Did I do something wrong ?
UPDATED:
because the code of the classes is too complex, I just simplified the logic.
When you call mo.ToObject<Class1>(); Newtonsoft.Json library will try to create an instance down the line. The problem is you cannot instantiate a abstract. You can see this your self by calling var x = new Class1(); somewhere in you code. This will give you error.
That being said, one thing you could do is create another class that inherits the abstract class.
public class NonAbstract : Class1 {}
this way you will have a class that can be instantiated. And then you can do this.
mo.ToObject<NonAbstract >();

Derived classes with derived properties

I have 2 classes that are both derived from a base class X. The base class contains a property of a class T. Both subclasses of X should contain a property that's derived from T.
What I would like to achieve is to declare the a property of T in the base class X and have it used in several methods, while using the same property of T in the derived classes of X but have it recognized as a derived class from T, so that I won't have to cast it every time I want to use it.
One of my solutions would be just remove the property from the base class and copy the methods for each derived class of X, but that would defeat the purpose of using inheritance.
Is anything like that achievable?
internal class TestObject
{
public string ID;
public XObject obj;
//....
}
internal class TestDocument : TestObject
{
public XDocument obj; //<--- want to be able to call obj in my methods
//as if it were an XDocument type but relate to the obj property in the base class
//....
}
internal class XObject
{
//....
}
internal class XDocument : XObject
{
//....
}
Generics should work for you:
class Base<T> where T: MyType
{
T MyProperty { get; set; }
public void DoSomething()
{
// do something with MyProperty
}
}
with MyType being the base-class of the property within Base.
Then in your derived class you can define the generic constraint, e.g.
class Derived : Base<DerivedType>
{
}
Now an instance of Derived has the property MyProperty of type DerivedType instead of MyType.
So in your case TestObject should be similar to this:
internal class TestObject<T> where T: XObject
{
public string ID;
public T obj;
//....
}
internal class TestDocument : TestObject<XDocument>
{
// obj is here of type XDocument
}
Make the type of the property a generic parameter of your base class:
class PropertyTypeBase { }
class PropertyTypeA : PropertyTypeBase { }
class Base<T> where T : PropertyTypeBase
{
public T Property { get; }
}
class Foo : Base<PropertyTypeA>
{
public Foo()
{
PropertyTypeBase x = Property;
PropertyTypeA a = Property;
}
}
The simplest way would be to make the base class generic, and constrain the generic parameter to be derived form a certain class:
class BaseProp { }
class DerivedPropA: BaseProp { }
class DerivedPropB : BaseProp { }
abstract class X<T>
where T: BaseProp
{
public T Value { get; set; }
public abstract void With(T value);
}
class A : X<DerivedPropA>
{
public override void With(DerivedPropA value)
{
this.Value = value;
}
}
class B : X<DerivedPropB>
{
public override void With(DerivedPropB value)
{
this.Value = value;
}
}
This is possible by using generics.
First, let me explain the example classes. Let's say these are your properties:
public class BaseHead {}
public class OrganicHead : BaseHead {}
public class CyborgHead : BaseHead {}
And you now want to implement these heads on your person classes:
public class BaseCreature {}
public class OrganicCreature : BaseCreature {}
public class CyborgCreature : BaseCreature {}
The solution:
public class BaseCreature<THead> where THead : BaseHead
{
public THead Head { get; set; }
public BaseCreature(THead head)
{
this.Head = head;
}
}
We make the BaseCreature generic
We limit the THead type to only allow types that either are BaseHead or are derived from BaseHead
However, we also want to ensure that the right creature (organic/cyborg) only uses the correct head (organic/cyborg). This can be done by deriving from a BaseCreature with a specific generic type:
public class OrganicCreature : BaseCreature<OrganicHead>
{
public OrganicCreature(OrganicHead head) : base(head)
{
}
}
CyborgCreature is analogous.
Suppose you wanted to make it possible that every creature can use every type of head. If that's what you want, then you need to keep the generic parameter generic:
public class OrganicCreature<THead> : BaseCreature<THead> where THead : BaseHead
{
public OrganicCreature(THead head) : base(head)
{
}
}
CyborgCreature is analogous.

C# Xml-Serialization of abstract base type into derived type - which TypeName property definition wins?

My scenario:
I have an object that I have defined with properties that are decorated with XmlElement tags and that have types that I have defined, some of which are typed as abstract that get set to respective derived types. I want to serialize this entire object into XML using XmlSerializer, and all properties that are abstract should get serialized as elements with TypeName set to the TypeName of the derived type.
This is an example of how the objects are structured:
[XmlType(TypeName = "MAINOBJECT")]
public class MainObject
{
[XmlElement(Type = typeof(DerivedClass))]
public BaseClass TheBase { get; set; }
}
[XmlInclude(typeof(DerivedClass))]
public abstract class BaseClass
{
[XmlAttribute("AnAttribute")]
public string AnAttribute { get; set; }
[XmlElement("ANELEMENT")]
public string AnElement { get; set; }
}
[XmlType(TypeName = "DERIVEDCLASS")]
public class DerivedClass : BaseClass
{
[XmlElement("ANOTHERELEMENT")]
public string AnotherElement { get; set; }
}
Note, however, that when I create a new instance of MainObject, populate it's properties and serialize it, this is what the generated XML looks like:
<MAINOBJECT>
<BaseClass AnAttribute="">
<ANELEMENT/>
<ANOTHERELEMENT/>
</BaseClass>
</MAINOBJECT>
What I want is this:
<MAINOBJECT>
<DERIVEDCLASS AnAttribute="">
<ANELEMENT/>
<ANOTHERELEMENT/>
</DERIVEDCLASS>
</MAINOBJECT>
Any clue what I'm doing wrong here?
Add the XmlElement name to TheBase in MainObject as follows:
[XmlType(TypeName = "MAINOBJECT")]
public class MainObject
{
[XmlElement("DERIVEDCLASS", Type = typeof(DerivedClass))]
public BaseClass TheBase { get; set; }
}
It seems to me that the best solution here would be to implement the IXmlSerializable interface so that you can have complete control over how the objects get serialized. Sure, it's more work, but if you have requirements like this that are somewhat out of the ordinary, then you may also run into more quirks where the standard XmlSerializer won't work for you down the road.
There is a good tutorial here: How to Implement IXmlSerializable Correctly
Also, there is some good information here: Proper way to implement IXmlSerializable?
Maybe not the best solution, but:
class Program
{
static void Main(string[] args)
{
XmlAttributes attrs = new XmlAttributes();
XmlElementAttribute attr = new XmlElementAttribute();
attr.ElementName = "DerivedClass";
attr.Type = typeof(DerivedClass);
attrs.XmlElements.Add(attr);
XmlAttributeOverrides attrOverrides = new XmlAttributeOverrides();
attrOverrides.Add(typeof(MainObject), "TheBase", attrs);
XmlSerializer s = new XmlSerializer(typeof(MainObject), attrOverrides);
StringWriter writer = new StringWriter();
MainObject mo = new MainObject { TheBase = new DerivedClass { AnAttribute = "AnAttribute", AnElement = "AnElement", AnotherElement = "AotherElement" } };
s.Serialize(writer, mo);
Console.Write(writer.ToString());
}
}

Serialization of class attributes?

Is the default XmlSerializer capable of serializing class attributes as Xml attributes?
[MyClassTypeAttribute(ClassType.MyClass)]
public MyClass : BaseClass {
}
would turn to
<myclass MyClassType="MyClass">
Reason:
I have a WCF service that sends me different objects through the same operation contract which all derive from BaseClass. To know which type of object it is and to cast it directly (and serialize it as Xml to write in a document afterwards), I'd like to have some 'type' attribute (enum).
One possibility is, of course, declaring a property as XmlAttribute
[XmlAttribute(params)]
public MyClassType { get; set; }
Problem here is: The XmlSerializer (DataContractSerializer as well, AFAIK) forces me to have a setter on every property. I know I can declare the setter as protected and it still works (XmlSerializer, you naughty little thing), but don't really like that solution because 1) I think there is a reason that I'm able to leave out the setter in POCOs usually and 2) declaring some properties as XmlAttributes and others as XmlElements is confusing (it's like putting dogs and cats into a cat goulash.
(Additionally, is it possible to force a derived class to declare certain attributes?)
[abstract MyClassTypeAttribute]
if it is about the type of your class here is an example:
[XmlIncludeAttribute(typeof(ConcreteFooOne))]
[XmlIncludeAttribute(typeof(ConcreteFooTwo))]
[XmlIncludeAttribute(typeof(ConcreteFooThree))]
[XmlRoot(ElementName = "FooData", Namespace = "http://foo.bar")]
public abstract partial class AbstractFoo
{
// Some abstract props etc.
}
[XmlRoot(ElementName = "FooData", Namespace = "http://foo.bar")]
public class ConcreteFooOne : AbstractFoo
{
public int MyProp { get; set; }
}
[XmlRoot(ElementName = "FooData", Namespace = "http://foo.bar")]
public class ConcreteFooTwo : AbstractFoo
{
}
[XmlRoot(ElementName = "FooData", Namespace = "http://foo.bar")]
public class ConcreteFooThree : AbstractFoo
{
}
class Program
{
static void Main(string[] args)
{
var serializer = new System.Xml.Serialization.XmlSerializer(typeof(AbstractFoo));
using (var stream = new FileStream("test.txt", FileMode.OpenOrCreate))
{
serializer.Serialize(stream, new ConcreteFooOne() { MyProp = 10 });
stream.Flush();
}
using (var stream = new FileStream("test.txt", FileMode.OpenOrCreate))
{
var c = serializer.Deserialize(stream);
}
}
}
The code will serialize and include the type attribute and when you deserialize you will get the right instance.

Dynamically add a Property to a System.object?

I got a list of different objects that I defined in different classes and I'd like to add a string property "Name" to all these objects. Is that possible ?
I don't have that much code to provide as my classes are very simple/classic ones.
Thanks in advance for any help !
(edit : I don't want to inherit from an abstract class that adds this property ! In fact, I don't want to modify at all my class that define my object. That's what i call "Dynamically" in the title.
What I want is something like :
myObject.AddProperty(string, "Name");
or
myObject.AddAttribute(string, "Name");
(I don't know how it is exactly called)
and then I can do :
myObject.Name = "blaaa";
Create an abstract class that all of your other classes could inherit:
public abstract class MyBaseClass
{
public string MyCommonString { get; set; }
}
public class Foo : MyBaseClass
{
public MyBaseClass() { }
}
//Create instance of foo
Foo myFoo = new Foo();
//MyCommonString is accessible since you inherited from base
string commonString = myFoo.MyCommonString;
EDIT (per new requirement)
Since you don't want to touch the original classes in the DLL, I'd take this [similar] approach:
public abstract class MyBaseClass
{
public string MyCommonString { get; set; }
}
//This class definition lives in the DLL and remains untouched
public class Foo
{
public Foo() { }
}
//This partial class definition lives in [insert new project name here]
public partial class Foo : MyBaseClass
{
public Foo () { }
}
Notice that Foo is now a partial class. You're not touching the existing class definition in the DLL, you're extending it.
EDIT (per newer new requirement)
Given your requirements (no editing of original class), what you're asking is not possible.
What you can do is to hard code a Hashtable named CustomProperties
Now you can fill this Hashtable with custom properties
Something like that:
MyClass myClass = new MyClass();
myClass.SetProperty("abc", 123);
myClass.SetProperty("bcd", "bla");
myClass.SetProperty("cde", DateTime.Now);
MessageBox.Show(myClass.GetProperty("abc").ToString());
class MyClass
{
private Hashtable MyProperties { get; set; }
public MyClass()
{
MyProperties = new Hashtable();
}
public object GetProperty(string name)
{
return MyProperties.Contains(name) ? MyProperties[name] : null;
}
public void SetProperty(string name, object value)
{
if (MyProperties.Contains(name))
MyProperties[name] = value;
else
MyProperties.Add(name, value);
}
}
You want to use the new C# 4.0 dynamic keyword:
dynamic obj = new System.Dynamic.ExpandoObject();
obj.Value = 10;
var action = new Action<string>((l) => Console.WriteLine(l));
obj.WriteNow = action;
obj.WriteNow(obj.Value.ToString());
You can not do this with object, but the ExpandoObject will do just fine.
But... overuse dynamic typing and you'll find yourself in a maintenance nightmare in the near future.

Categories

Resources