I am trying to serialize following class hierarchy:
public class Control
{
public virtual string Name {get; set;}
public virtual string Type {get; set;}
public virtual string Text { get; set; }
public virtual SerializableFont Font { get; set; }
private Operation op = new Operation();
public Operation Events { get { return op; } }
}
[System.Xml.Serialization.XmlInclude(typeof(Control))]
public class TextProperties : Control
{
public Label txt;
public TextProperties()
{
}
public override string Type
{
get { return "Text"; }
}
public override string Text
{
get { return txt.Text; }
set
{
txt.Text = value;
}
}
public override SerializableFont Font
{
get { return new SerializableFont(txt.Font); }
set
{
txt.Font = new SerializableFont().Font ;
}
}
}
As you can see I am including the base class but still its throwing following exception:
The type TextProperties was not expected. Use the
XmlInclude or SoapInclude attribute to specify types that are not
known statically.
I´m not sure that the problem is really your class hierarchy itself, it seems to be okay. You dont need to add the attribute.
Instead, you are likely trying to read/write an object of type TextProperties with an XmlSerializer created for objects of type Control. That won´t work, you need to use the serializer created specific to the type to serialize / deserialize.
If this is not known at compile time, try to create a wrapping class that implements IXMLSerializable. When reading, this class must first read data to define the class of the wrapped object (a node attribute named "TypeName", for example). It must then create the specific serializer for the given type at runtime and use it to load the wrapped object.
EDIT: Here is some sample code how it could be done. You will need to implement GetTypeByName yourself (eg. crawling through all loaded assemblies or just "hardwiring" some strings to a specific type you expect). The code should suffice to be integrated into a class with a property "WrappedObject".
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
reader.MoveToContent();
var typeName = reader.GetAttribute("TypeName");
reader.ReadStartElement();
var serializer = new XmlSerializer(GetTypeByName(typeName));
WrappedObject = serializer.Deserialize(reader);
reader.ReadEndElement();
}
public void WriteXml(XmlWriter writer)
{
writer.WriteAttributeString("TypeName", "", GetTypeByName(WrappedObject));
var serializer = new XmlSerializer(typeof(WrappedObject));
serializer.Serialize(writer, WrappedObject);
}
I think you need to put attribute above the parent class like this
[XmlInclude(typeof(ChildClass))]
[Serializable]
public abstract class ParentClass
{
public abstract string Name { get; set; }
}
in child class you put
[Serializable]
public class ChildClass: ParentClass
{
}
Related
I've found couple of questions on the same topic here, however I couldn't find what I need. Basically I am searching for this kind of magic:
public class BaseClass
{
public int DerivedТype { get; set; }
}
public class DerivedClass<T> : BaseClass
{
public DerivedClass(T initialValue)
{
DerivedТype = 1;
Property = initialValue;
}
public T Property { get; set; }
}
public class OtherDerivedClass<T> : BaseClass
{
public OtherDerivedClass(T initialValue)
{
DerivedТype = 2;
OtherProperty = initialValue;
}
public T OtherProperty { get; set; }
public int OtherProperty2 { get; set; }
public float OtherProperty { get; set; }
}
public class Program
{
public static void Main()
{
List<BaseClass> baseClassList = new List<BaseClass>();
baseClassList.Add(new DerivedClass<int>(5));
baseClassList.Add(new OtherDerivedClass<float>(6));
foreach (var derived in baseClassList)
{
if (derived.DerivedТype == 1)
{
Console.WriteLine(derived.Property);
}
else if (derived.DerivedТype == 2)
{
Console.WriteLine(derived.OtherProperty);
}
}
}
}
I want a list of BaseClass where I can insert instances of DerivedClass and OtherDerivedClass. So far so good.
DerivedClass and OtherDerivedClass hold different properties so I really have no idea how access them. Also I don't want to use any weired casts. So this part of the code prevents me from building.
if (derived.DerivedТype == 1)
{
Console.WriteLine(derived.Property);
}
else if (derived.DerivedТype == 2)
{
Console.WriteLine(derived.OtherProperty);
}
Any ideas would be appreciated. Thank you in advance!
This looks like a problem that can be solved with polymorphism. I'll make a version of your app that does exactly what you seem to be doing in your example, but if there was more information as to what your target goal is, the solution may be different.
public abstract class BaseClass
{
public abstract void DoSomething();
public abstract void GetData(Dictionary<string,string> container);
}
public class DerivedClass<T> : BaseClass
{
public DerivedClass(T initialValue)
{
Property = initialValue;
}
public T Property { get; set; }
public override void DoSomething()
{
Console.WriteLine(Property);
}
public override void GetData(Dictionary<string,string> container)
{
container.Add(nameof(Property), "{Property}");
}
}
public class OtherDerivedClass<T> : BaseClass
{
public OtherDerivedClass(T initialValue)
{
OtherProperty = initialValue;
}
public T OtherProperty { get; set; }
public int OtherProperty2 { get; set; }
public override void DoSomething()
{
Console.WriteLine(OtherProperty);
}
public override void GetData(Dictionary<string,string> container)
{
container.Add(nameof(OtherProperty), "{OtherProperty}");
container.Add(nameof(OtherProperty2), "{OtherProperty2}");
}
}
Your foreach loop could then be as simple as:
foreach(var derived in baseClassList) derived.DoSomething();
This is the proper way to do something like this using OO. There's no need for the DerivedType integer since the object knows what type of class it is and what to do. This is why one would use polymorphism. It's simple and elegant and OO. Extend or change the DoSomething to be more appropriate for what you're trying to do.
The OP came up with his own solution, but if the goal is to do something with the data that is more meaningful, you could also pass in an object to an abstract method that allows you to do this. I added a GetData method that will return all of the property values as strings. The second type of the dictionary could also be object with the actual value stored in the dictionary.
BaseClass could also be a regular class with a method in it to return an IDictionary of object values with string keys. The method could use reflection to get all property values for whatever class it is the base of. Reflection has much more overhead, though, so is not the most efficient way to do this from an execution standpoint.
The correct way to check if an object is a certain type is to use the is operator such as:
if(derived is DerivedType<int>)
{
// Do what you need to do with the specific object type
}
If you know you're going to cast the object, as pointed out by Adosi, you would use:
var castedValue = derived as DerivedType<int>;
if(castedValue != null)
{
// Do what you need to do with castedValue
}
A null will be returned if the object isn't of type DerivedType<int>. Trying to use (DerivedType)derived would cause an invalid cast exception.
To the best of my knowledge what you want is between impossible and not a good idea. Typechecking is done at compile time. Stuff like Dynamic can move those checks to runtime, but it results in all kinds of issues (functions that take dynamic parameters also return dynamic).
If you got at least C# 7.0, you can at least write a switch for it. Old switch only supported values vs constants for a few select value types and string. But C# 7.0 introduces pattern matching. With that you could even use a is check as part of a case.
Thank you all for the awesome support! I decided to go simple and just use a cast.
public class BaseClass
{
public int DataТype { get; set; }
public object Data { get; set; }
}
public class DataClass<T>
{
public DataClass(T initialValue)
{
Property = initialValue;
}
public T Property { get; set; }
}
public class Program
{
public static void Main(string[] args)
{
List<BaseClass> listBaseClass = new List<BaseClass>();
BaseClass dummy = new BaseClass();
dummy.DataТype = 1;
dummy.Data = new DataClass<int>(50);
listBaseClass.Add(dummy);
if (listBaseClass[0].DataТype == 1)
{
DataClass<int> casted = (DataClass<int>)listBaseClass[0].Data;
Console.WriteLine(casted.Property);
}
}
}
Is it possible to add different type of generic objects to a list?. As below.
public class ValuePair<T>
{
public string Name { get; set;}
public T Value { get; set;
}
and let say I have all these objects...
ValuePair<string> data1 = new ValuePair<string>();
ValuePair<double> data2 = new ValuePair<double>();
ValuePair<int> data3 = new ValuePair<int>();
I would like to hold these objects in a generic list.such as
List<ValuePair> list = new List<ValuePair>();
list.Add(data1);
list.Add(data2);
list.Add(data3);
Is it possible?
In general, you'd have to either use a List<object> or create a non-generic base class, e.g.
public abstract class ValuePair
{
public string Name { get; set;}
public abstract object RawValue { get; }
}
public class ValuePair<T> : ValuePair
{
public T Value { get; set; }
public object RawValue { get { return Value; } }
}
Then you can have a List<ValuePair>.
Now, there is one exception to this: covariant/contravariant types in C# 4. For example, you can write:
var streamSequenceList = new List<IEnumerable<Stream>>();
IEnumerable<MemoryStream> memoryStreams = null; // For simplicity
IEnumerable<NetworkStream> networkStreams = null; // For simplicity
IEnumerable<Stream> streams = null; // For simplicity
streamSequenceList.Add(memoryStreams);
streamSequenceList.Add(networkStreams);
streamSequenceList.Add(streams);
This isn't applicable in your case because:
You're using a generic class, not an interface
You couldn't change it into a generic covariant interface because you've got T going "in" and "out" of the API
You're using value types as type arguments, and those don't work with generic variable (so an IEnumerable<int> isn't an IEnumerable<object>)
Not unless you have a non-generic base-type ValuePair with ValuePair<T> : ValuePair (it would work for an interface too), or use List<object>. Actually, though, this works reasonably:
public abstract class ValuePair
{
public string Name { get; set; }
public object Value
{
get { return GetValue(); }
set { SetValue(value); }
}
protected abstract object GetValue();
protected abstract void SetValue(object value);
}
public class ValuePair<T> : ValuePair
{
protected override object GetValue() { return Value; }
protected override void SetValue(object value) { Value = (T)value; }
public new T Value { get; set; }
}
No, it is not possible. You could create, in your case, a base class ValuePair from which ValuePair<T> derives. Depends on your purposes.
it's not possible as far as I know.
the line:
List<ValuePair> list = new List<ValuePair>();
you wrote in your sample is not providing a concrete type for T and this is the issue, once you pass it, you can only add object of that specific type.
Here is a piece of sample code to explain my question:
public class TheBaseClass
{
public list<int> BaseClassList {get; set;}
}
public class TheDerivedClass : TheBaseClass
{
//here I want to indicate the XmlSerializer to serialize the 'BaseClassList' with a different name 'DerivedClassList'
}
I know how to do this when the variable is in the same class by using [XmlElement( ElementName = "DesiredVarName")] but want to know if it is possible to do this in a derived class at all? If yes, how?
From your comment, it appears you are able to make changes to TheBaseClass. Thus you can add a virtual bool ShouldSerialize{PropertyName}() method for the BaseClassList property in the base class and return true. Then override it in the derived class and return false, and introduce a proxy property with the desired name:
public class TheBaseClass
{
public List<int> BaseClassList { get; set; }
public virtual bool ShouldSerializeBaseClassList() { return true; }
}
public class TheDerivedClass : TheBaseClass
{
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DebuggerBrowsable(DebuggerBrowsableState.Never)]
public List<int> DerivedClassList { get { return BaseClassList; } set { BaseClassList = value; } }
public override bool ShouldSerializeBaseClassList() { return false; }
}
For an explanation of why this works see Defining Default Values with the ShouldSerialize and Reset Methods.
One thing that comes to mind is to use XmlAttributeOverrides:
var attributes = new XmlAttributes();
attributes.XmlElements.Add(new XmlElementAttribute("DerivedClassList"));
var overrides = new XmlAttributeOverrides();
overrides.Add(typeof(TheBaseClass), "BaseClassList", attributes);
var serializer = new XmlSerializer(typeof(TheDerivedClass), overrides);
In this example we are programatically passing to the XmlSerializer a list of custom serialization attributes that will be applied.
We have a custom ConfigurationManager library that serializes/deserializes a config.json file into an ExpandoObject.
Would it be possible to create a custom attribute that overrides the Getter/Setter of these properties to abstract this ExpandoObject?
Ideally I would be able to use the Attribute like this:
[System.AttributeUsage(System.AttributeTargets.Property)]
class Configureable : System.Attribute
{
public string Default { get; set; }
public bool IsEncrypted { get; set; }
}
class Test
{
[Configureable(Default = "0",IsEncrypted = false)]
public string MyValue { get; set; }
}
When I set the value of the decorated property I want to auto-magically update the value of the ExpandoObject, which would then in turn force an update be written to my config.json file.
When I access the value of the decorated property I want the getter to actually return the value of the underlying ExpandoObject. I can do this by manually having the developer modify the getter/setter. I was wondering if I could also do this with code inside of the attribute.
Thank you!
I found http://doc.postsharp.net/location-interception
That seems to do exactly what I want.
[System.AttributeUsage(System.AttributeTargets.Property)]
[Serializable]
class Configureable : LocationInterceptionAspect
{
public string Default { get; set; }
public bool IsEncrypted { get; set; }
public override void OnGetValue(LocationInterceptionArgs args)
{
base.OnGetValue(args);
if (args.Value == null)
{
}
}
public override void OnSetValue(LocationInterceptionArgs args)
{
//base.OnSetValue(args);
}
}
class Test
{
[Configureable(Default = "0",IsEncrypted = false)]
public string MyValue { get; set; }
}
ExpandoObject is a dictionary with object syntax. It is useful only in simple scenarios. If you need complex logic, use DynamicObject intead. Override its TryGetMember and TrySetMember methods to replicate functionality of ExpandoObject, then customize logic of these methods in the way you want.
It's not clear what your requirements are though. If you have a class which holds properties, what is the point of having dynamic objects?
Say I have code out there like this:
public class Base // I cannot change this class
{
public string Something { get; private set; }
public string Otherthing { get; set; }
public static Base StaticPreSet
{
get { return new Base { Something = "Some", Otherthing = "Other"}; }
}
public static Base StaticPreSet2
{
get { return new Base { Something = "Some 2", Otherthing = "Other 2"}; }
}
}
public class SubClass : Base // I can change this class all I want.
{
public string MoreData { get; set; }
// How can I wrap the PreSets here so that they return SubClass objects?
// Something like this:
public static SubClass MyWrappedPreset
{
get
{
// Code here to call the base preset and then use it as the
// base of my SubClass instance.
}
}
}
What makes this complicated is the Something property. It has a private setter. So I can't set it in the subclass. The only way it can be set is is via the preset properties.
Is there a way to wrap the StaticPreSet property in my SubClass so that it will return an object of type SubClass?
// I cannot change this base class.
Given that you can't change the base class, there is no way to cause it to change behavior (ie: return a different class at runtime).
If you could influence the design of the base class static methods, you could redesign it in a way to be flexible enough to provide this functionality. However, without changing it, this won't work.
Edit in response to edit:
You could create a new static method that does what you are showing, like so:
public static SubClass MyWrappedPreset
{
get
{
// Code here to call the base preset and then use it as the
// base of my SubClass instance.
Base baseInstance = Base.StaticPreSet;
SubClass sc = new SubClass(baseInstance); // Create a new instance from your base class
return sc;
}
}
However, this provides a completely new, unrelated property - you'd have to access it via SubClass.MyWrappedPreset, not the Base class.
Static fields in a class "have nothing to do with it".
Basically, except access to private static fields, id doesn't matter in which class you put them - they behave the same.
If you inherit a class, and you declare another static field with the same name of a static field on the base class, you will simply 'hide' it. Example for you:
using System;
public class Base // I cannot change this class
{
public string Something { get; set; }
public string Otherthing { get; set; }
public static Base StaticPreSet
{
get { return new Base { Something = "Some", Otherthing = "Other"}; }
}
public static Base StaticPreSet2
{
get { return new Base { Something = "Some 2", Otherthing = "Other 2"}; }
}
}
public class SubClass : Base // I can change this class all I want.
{
public string MoreData { get; set; }
public static SubClass StaticPreSet2
{
get { return new SubClass { Something = "inherited", Otherthing=""}; }
}
}
public class Test
{
public static void Main()
{
Console.WriteLine(SubClass.StaticPreSet2.Something);
}
}
Will write "inherited".