Serializing a List hold an interface to XML - c#

I have been reading around but I have not come across a solution to my problem
I am currently working with a Business Object that will hold all my data and we need to convert this object to and from XML.
My object holds a list of Actions (List...), but there are 2 action types (for now).
I have to action types SimpleAction and CompositeAction, and they both inherit from IAction allowing them to both be held in the Actions list.
Now you can probably see the problem as Interfaces cannot be serialized as they hold no data.
How, with maybe some sample code, do I write a Class or Serializer that gets that object type and performs then serializes object with the correct type?
Some code:
[XmlArray("Actions")]
public List<IAction> Actions { get; set; }
public interface IAction
{
int ID { get; set; }
ParameterCollection Parameters { get; set; }
List<SectionEntity> Validation { get; set; }
TestResultEntity Result { get; set; }
string Exception { get; set; }
}
[XmlType("A")]
public class SimpleActionEntity : IAction
{
#region IAction Members
[XmlAttribute("ID")]
public int ID { get; set; }
[XmlIgnore]
public ParameterCollection Parameters { get; set; }
[XmlIgnore]
public List<SectionEntity> Validation { get; set; }
[XmlIgnore]
public TestResultEntity Result { get; set; }
[XmlElement("Exception")]
public string Exception { get; set; }
#endregion
}
Any help would be greatly appreciated. :)

You can use XmlArrayItemAttribute, As we discussed it's no good to create a list of IAction so it's good to create base class
public interface IAction {}
public abstract class ActionBase : IAction {}
public class SimpleAction : ActionBase {}
public class ComplexAction : ActionBase {}
[XmlArray("Actions")]
[XmlArrayItem(typeof(SimpleAction)),XmlArrayItem(typeof(ComplexAction))]
public List<ActionBase> Actions { get; set; }
In fact you also can control Element names in the xml file like this:
[XmlArray("Actions")]
[XmlArrayItem(typeof(SimpleAction),ElementName = "A")]
[XmlArrayItem(typeof(ComplexAction),ElementName = "B")]
public List<ActionBase> Actions { get; set; }

Ok I have created a solution that I feels does what I want pretty well.
What I did is rather than holding
[XmlArray("Actions")]
public List<IAction> Actions { get; set; }
I decided to create an ActionsCollection class that handled the List BUT also allowed me to use IXMLSerializable to override the ReadXml and WriteXML methods so that I could handle the way the list is Serialized and Deserialized.
[XmlElement("Actions")]
public ActionCollection Actions { get; set; }
public class ActionCollection: CollectionBase, IXmlSerializable
{
#region IList Members
...
#endregion
#region ICollection Members
...
#endregion
#region IEnumerable Members
...
#endregion
#region IXmlSerializable Members
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
//TODO
}
public void WriteXml(System.Xml.XmlWriter writer)
{
foreach (IAction oAction in List)
{
XmlSerializer s = new XmlSerializer(oAction.GetType());
s.Serialize(writer, oAction);
}
}
#endregion
}

Maybe if you derive your two action classes from a common abstract base class that implements the interface?
public interface IAction {}
public abstract class ActionBase : IAction {}
public class SimpleAction : ActionBase {}
public class ComplexAction : ActionBase {}
Then instead of using List<IAction>, use List<ActionBase>.

Related

Generics: cast derived class back to it's parent super class

I have three base classes:
public class ItemBase
{
public string Name { get; set; }
}
public class ProductBase<T> : ItemBase
where T : ItemBase
{
public List<T> Modifiers { get; set; }
public List<T> GroupModifiers { get; set; }
}
public class ModifierBase<T> : ItemBase
where T : ItemBase
{
public List<T> ChildModifiers { get; set; }
}
And two derived classes:
public class Product : ProductBase<Modifier>
{
public string Some_Product_Specific_Property { get; set; }
}
public class Modifier : ModifierBase<Modifier>
{
public string Some_Modifier_Specific_Property { get; set; }
}
The intent behind all this is to have different sets of derived classes like Product and ProductFromOtherSystem each with it's own specific properties but with the same basic properties.
And now I need to process basic properties of any class derived from ProductBase<T>.
For this purpose I want to use something like this:
public static void DoSomething(ProductBase<ModifierBase<ItemBase>> item)
{
Console.WriteLine(item.Name);
}
The issue here is that I cannot pass parameters to it:
Product product1 = new Product();
DoSomething(product1);
ProductFromOtherSystem product2 = new ProductFromOtherSystem();
DoSomething(product2 as ProductBase<ModifierBase<ItemBase>>);
The error is like
Cannot convert type _ to _ via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion
I've tried to downcast it somehow but have not found any solution. I wonder if it is possible to do it?

Error using the generic type BaseUser requires 1 argument

I have an interface
public interface IIdentity<T>
{
T GetUser();
}
I have a base class that implements the Interface as an abstract method
public abstract class BaseUser<T> : IIdentity<T>
{
public string UserId { get; set; }
public string AuthType { get; set; }
public List<Claim> Claims { get; set; }
public abstract T GetUser();
}
In the class that inherits the base class
public class JwtUser : BaseUser
{
public string Sub { get; set; }
}
I get an error using the generic type BaseUser requires 1 argument, what do i do here, basically I'd like my user to inherit shared properties from the base class which it does (i think) and to implement the generic method from the base class as I'm going to have different types of users (JWT/Windows etc) I need to abstract away the getUsers method, hope that makes sense ?
You have to ways to implement this, both require to set the generic in BaseUser.
You could expose that generic:
public class JwtUser<T> : BaseUser<T>
{
public string Sub { get; set; }
}
Or, just set the generic:
public class JwtUser : BaseUser<JwtUser>
{
public string Sub { get; set; }
}
it should be like , for Ref : Generic Classes (C# Programming Guide)
public class JwtUser<User> : BaseUser<User>
{
public string Sub { get; set; }
}
or
public class JwtUser<T> : BaseUser<T>
{
public string Sub { get; set; }
}
and when create instace
var jwtUser =new JwtUser<User> ();
or
class JwtUser: BaseUser<JwtUser> { }
In all way at the end you must need to specify value for T template as its generic.
For example if you take List<T> for using it you must need to intialize with proper type like if interger list then List<int> intlist = new List<int>();

Cast concrete type to nested generic base type

Let's say I have nested generic data classes similar to the following:
public class BaseRecordList<TRecord, TUserInfo>
where TRecord : BaseRecord<TUserInfo>
where TUserInfo : BaseUserInfo
{
public virtual IList<TRecord> Records { get; set; }
public virtual int Limit { get; set; }
}
public class BaseRecord<TUserInfo>
where TUserInfo : BaseUserInfo
{
public virtual DateTime CreationTime { get; set; }
public virtual TUserInfo UserInfo { get; set; }
}
public class BaseUserInfo
{
public virtual string Name { get; set; }
public virtual int Age { get; set; }
}
With 2 concrete versions like so:
// Project 1: Requires some extra properties
public class Project1RecordList : BaseRecordList<Project1Record, Project1UserInfo> {}
public class Project1Record : BaseRecord<Project1UserInfo>
{
public Guid Version { get; set; }
}
public class Project1UserInfo : BaseUserInfo
{
public string FavouriteFood { get; set; }
}
and
// Project 2: Some properties need alternate names for JSON serialization
public class Project2RecordList : BaseRecordList<Project2Record, Project2UserInfo>
{
[JsonProperty("allRecords")]
public override IList<Project2Record> Records { get; set; }
}
public class Project2Record : BaseRecord<Project2UserInfo> {}
public class Project2UserInfo : BaseUserInfo
{
[JsonProperty("username")]
public override string Name { get; set; }
}
I'm then happy to have 2 repositories that return Project1RecordList and Project2RecordList respectively, but at some point in my code I find myself needing to be able to handle both of these in one place. I figure that at this point I need to be able to treat both of these types as
BaseRecordList<BaseRecord<BaseUserInfo>, BaseUserInfo>
as this is the minimum required to meet the generic constraints, but trying to cast or use "as" throws up errors about not being able to convert.
Is there any way to do this, or even a more sane way to handle this situation without massive amounts of code duplication? If it makes any difference this is for a web app and there are already a large number of data classes, many of which use these nested generics.
What you are talking about is called covariance and MSDN has a great article on this here: https://msdn.microsoft.com/en-us/library/dd799517(v=vs.110).aspx
First, create a new interface:
interface IBaseRecord<out TUserInfo>
where TUserInfo : BaseUserInfo
{
}
Have BaseRecord inherit from the new interface:
public class BaseRecord<TUserInfo> : IBaseRecord<TUserInfo>
where TUserInfo : BaseUserInfo
{
public virtual DateTime CreationTime { get; set; }
public virtual TUserInfo UserInfo { get; set; }
}
If done right, this should compile:
IBaseRecord<BaseUserInfo> project1 = new Project1Record();
IBaseRecord<BaseUserInfo> project2 = new Project2Record();
To expand this to the BaseRecordList, create IBaseRecordList:
interface IBaseRecordList<out TRecord, out TUserInfo>
where TRecord : IBaseRecord<TUserInfo>
where TUserInfo : BaseUserInfo
{
}
Have BaseRecordList inherit from that:
public class BaseRecordList<TRecord, TUserInfo> : IBaseRecordList<TRecord, TUserInfo>
And then use as such:
IBaseRecordList<IBaseRecord<BaseUserInfo>, BaseUserInfo> project1 = new Project1RecordList();
IBaseRecordList<IBaseRecord<BaseUserInfo>, BaseUserInfo> project2 = new Project2RecordList();
Once you have that setup, just add whatever properties or functions you need to use generically to the interfaces.

How to force implementation of an abstract classes members in the inheriting class?

I have the following two classes:
abstract class LogItem {
public String payload { get; set; }
public String serverId { get; set; }
public DateTime timeRecieved { get; set; }
}
class MyLogItem : LogItem
{
//No I want this to have to have the members from the abstract class above, as if it where an interface?
}
So in other words I am wanting a type if interface that can have definitions or variables which all classes that implement it have to have, but they could add more if they required ?
The above example builds, even if i dono add the members from the abstract class.
edit
Forget what I've said before. These are attributes, not methods. For them to be accessible on derived classes, you make them protected or public. The difference is that public members are visible to the world, while protected ones are visible to the class and subclasses.
Any class derived from your LogItem may have other variables.
abstract class LogItem {
public String payload { get; set; }
public String serverId { get; set; }
public DateTime timeRecieved { get; set; }
}
class MyLogItem : LogItem
{
//No I want this to have to have the members from the abstract class above, as if it where an interface?
private void TestMethod(){
String test = payload;
}
}
check out this post for more information
Your MyLogItem class can reference any of the above members directly. They are accessible
You may declare an interface with those
public interface MyInterface {
public String payload { get; set; }
public String serverId { get; set; }
public DateTime timeRecieved { get; set; }
}
and your class
public class MyLogItem : MyInterface
{
String _payload;
public String payload { get{ return _payload; } set {_payload=value;} }
...
}
The abstract keyword can also be applied to methods, as described here.

how to mark an interface as DataContract in WCF

i have two data classes which hold only data members(no functions). One is CallTask the other is SmsTask. These two classes have some common properties like ID, Tel. I put these common properties in a seperate interface class and i use this interface class in my project whenever appropriate.
Now i added a WCFService to my project to share data between clients and server. Consider the following class design:
public interface IGsmTask : IComparable
{
string TaskID { get; set; }
string SessionID { get; set; }
string Tel { get; set; }
}
class CallTask : IGsmTask
{
#region IGsmTask Members
public string TaskID { get; set; }
public string SessionID { get; set; }
public string Tel { get; set; }
#endregion
}
class SmsTask : IGsmTask
{
#region IGsmTask Members
public string TaskID { get; set; }
public string SessionID { get; set; }
public string Tel { get; set; }
#endregion
public string SmsText { get; set; }
}
in this design, i want to host CallTask, SmsTask, and IGsmTask to the clients to use these in service methots like the following;
[OperationContract]
public void AddTask(IGsmTask task)
{
}
i tried to mark [DataContract] on IGsmTask but it gives me complition error. Isnt there any methot that i can use interfaces as DataContracts? Or how should i use KnownAttributes types in this synerio?
Thanks.
As far as I know using interfaces as datacontracts is not possible. You may use a base class and add knowntype attributes on the otherhand.
Fer: Everything is Possible with the right design.
If the issue is:
a class is a data contract
&&
1 or more of its properties must be an interface...
public interface ICustomInterface
{
int Property1 {get;set}
}
[DataContract]
public class MyClass
{
[DataMember(Name="_myInterface")]
public ICustomInterface MyInterface {get;set;}
}
The issue is that when the de-serialization occurs --
There is no way to turn the data into a class that implements ICustomInterface.
The Solution is to create a concrete class that does Implement the interface, and cast the getter/setter of the public property (that is of type interface) into a private property of the concrete class.
public class CustomInterfaceImplementor: ICustomInterface
{
public int Property1 {get;set;}
}
[DataContract]
public class MyClass
{
[DataMember(Name="_myInterface")]
private CustomInterfaceImplementor _MyInterface;
public ICustomInterface MyInterface
{
get {return (_MyInterface as ICustomInterface);}
set {_MyInterface = (value as CustomInterfaceImplementor);}
}
}

Categories