subclassing and data contracts - c#

I'm playing with the following code:
[ServiceContract]
public interface IUserAccountService
{
[OperationContract]
UserAccountResponse CreateNewUserAccount(UserAccountRequest userAccountRequest);
}
public abstract class BaseResponse
{
public bool Success { get; set; }
public string Message { get; set; }
}
public class UserAccountResponse : BaseResponse
{
public int NewUserId { get; set; }
}
My questions are:
Do I need to add the DataContract attribute to both the abstract class and the subclass?
If the abstract class does not need the DataContract attribute, can I add the DataMember attribure to its properties?

If you want items in the base class to be serialized, then you must apply DataContract to the base class and apply DataMember to those items that are to be serialized in the base class. However, if you do not want anything in the base class to be serialized, then you shouldn't need to specify DataContract on the base class.
From the MSDN documentation:
"When you apply the DataContractAttribute to a base class, the derived types do not inherit the attribute or the behavior. However, if a derived type has a data contract, the data members of the base class are serialized. However, you must apply the DataMemberAttribute to new members in a derived class to make them serializable."

Yes you will have to use [DataContract] on both BaseResponse and UserAccountResponse. You will also have to use the [KnownType] attribute for every subclass as shown below.
[KnownType(typeof(UserAccountResponse))]
[DataContract]
public abstract class BaseResponse
{
...
}

Related

ProtoBuf is not serializing a field in inherited class [duplicate]

This question already has answers here:
How to Serialize Inherited Class with ProtoBuf-Net
(2 answers)
Closed 6 years ago.
I have a base class called PrivilegeType and it's inherited by various other classes.
Everything works fine except for one specific field called PossibleValues which doesn't get serialized/deserialized well.
Base class definition:
[ProtoContract]
[ProtoInclude(13, typeof(PrivilegeEnum))]
public abstract class PrivilegeType {
...
}
PrivilegeEnum definition:
[ProtoContract]
public class PrivilegeEnum : PrivilegeEnumLike<PrivilegeEnumValue> {
...
}
PrivilegeEnumLike<T> definition:
[ProtoContract]
public abstract class PrivilegeEnumLike<T> : PrivilegeType<T>
{
[ProtoMember(2)]
public Dictionary<string, PrivilegeEnumValue> PossibleValues;
...
}
PrivilegeEnumValue definition:
[ProtoContract]
public class PrivilegeEnumValue
{
[ProtoMember(1)]
public string Value;
[ProtoMember(2)]
public string Text;
[ProtoMember(3)]
public HashSet<PrivilegeEnumValue> ImpliedValues = new HashSet<PrivilegeEnumValue>();
...
}
The thing is, that field is defined inPrivilegeEnumLike<T> which is not included in ProtoInclude list itself, but its subclasses are. I can't add PrivilegeEnumLike<> to ProtoInclude list because I guess it doesn't make sense.
Here's the rule:
Class hierarchy must be implemented correctly.
This means you need to use ProtoInclude on parent classes, NOT necessarily base classes
Otherwise, any inherited class between your subclass and baseclass will not get serialized.
What I did:
Base class:
[ProtoContract]
[ProtoInclude(12, typeof(PrivilegeEnumLike<PrivilegeEnumValue>))]
[ProtoInclude(13, typeof(PrivilegeEnumLike<PrivilegeEnumValue[]>))]
public abstract class PrivilegeType
Middle class:
[ProtoContract]
[ProtoInclude(20, typeof(PrivilegeEnum))]
[ProtoInclude(21, typeof(PrivilegeEnumSet))]
public abstract class PrivilegeEnumLike<T> : PrivilegeType<T>
Everything works correctly now.
Please let me know if there's any better solution to this.

base class collection defined by derived class

I'm not even close to as experienced in C# as I am in C++, but trying to get better.
In C#, does there exist a way to create a base class that contains a property which is a List and then in the derived class define what T is for that concrete type?
public class Base
{
public List<T> Data { get; set; }
}
public class Derived : Base
{
// Declare to the world you use Base.data<Elephant>
// Callers of my Data property get Elephants
}
I imagine not, since you can no longer act on the interface in the base class since you wouldn't know what type you are getting until you know what type the actual instance is, but maybe there is some magical thing in C# that is similar to this?
You can make the base class generic like this:
public class Base<T>
{
public List<T> Data { get; set; }
}
And then when you create the derived class, you can specify T like this:
public class Derived : Base<Elephant>
{
}
For the consumers of Derived, the type of the Data property is List<Elephant>.

Serialize delivered class's instance using DataContract

I have library with class in it looks like next:
[DataContract]
class MyBaseClass
{
public string Name { get; set; }
}
Also, I have another project with ref of this library and class in it looks like:
[DataContract]
class MyDeliveredClass : MyBaseClass
{
public string SecondName { get; set; }
}
I wonder how could I serialize list<MyBaseClass> which could contain objects of MyBaseClassand MyDeliveredClass ?
May be I should use [KnownType(MyDeliveredClass)]... but I have no reference to MyDeliveredClass in library...
If you declare both MyBaseClass and MyDeliveredClass as Service known types on the service contract interface then that should do the trick:
[ServiceContract(SessionMode = SessionMode.Required, ...)]
[ServiceKnownType(typeof(MyBaseClass ))]
[ServiceKnownType(typeof(MyDeliveredClass ))]
public interface IMySerivceContract {
...
}
Generally you have to choice between delclaring as KnownTypes on the class declaration or as ServerKnownTypes on the service interface. However sometimes the KnownType route is not an option for various reasons - one of which is your situation where you dont have access to a class declaration. Another case where you are forced to use ServiceKnownTypes is if your contract uses interfaces instead of the base class i.e if your contract had List<IMyBaseInterface>.

Abstract fields aren't allowed. How do I force a derived class to instantiate/initialize a field?

I have an abstract base class for a generic 'Device' type and would like to require the derived specific device classes to initialize a list based on their respective differences.
When one sets the derived class to active it must go through the list to set the parameters to active as well. Each derived class will insert their own parameters into the list.
Here is the relevant code:
Base class:
abstract public class Device : Common, IDisposable
{
abstract public Boolean bActive
{
get;
set;
}
abstract List<Parameters> ActiveParameters;
...
}
I don't wish to initialize the List in the base class because I do not know which parameters are going to be inserted into the list from the derived class. This code produces an error saying that I cannot have an abstract field and I understand that but is there a way to require a derived class to initialize a field from the base class?
This code produces an error saying that I cannot have an abstract field and I understand that but is there a way to require a derived class to initialize a field from the base class?
If this is required to be implemented, it should be part of your API. To handle this, you can make this a protected property. This will force it to be implemented by all derived classes.
protected abstract List<Parameters> ActiveParameters { get; }
If this is about initializing the list, then you can force that by putting that list into the constructor (or all constructors, if you have more of them) of the base class.
Something like:
public abstract class Device : Common, IDisposable
{
protected Device(List<Parameters> activeParameters)
{
ActiveParameters = activeParameters;
}
protected List<Parameters> ActiveParameters { get; private set; }
}
The derived class will be then forced to do something like:
public class ConcreteDevice : Device
{
public ConcreteDevice()
: base(new List<Parameters>())
{}
}

Honouring of AttributeUsage on derived attribute types

Given the following, I would not expect the compiler to allow multiple attributes that are derived from the base attribute, given that is set to AllowMultiple=false. In fact it compiles without a problem - what am I missing here?
using System;
[AttributeUsage(AttributeTargets.Property,AllowMultiple=false,Inherited=true)]
abstract class BaseAttribute : Attribute { }
sealed class DerivedAttributeA : BaseAttribute { }
sealed class DerivedAttributeB : BaseAttribute { }
class Sample1
{
[DerivedAttributeA()]
[DerivedAttributeB()]
public string PropertyA{ get; set; } // allowed, concrete classes differ
[DerivedAttributeA()]
[DerivedAttributeA()]
public string PropertyB { get; set; } // not allowed, concrete classes the same, honours AllowMultiple=false on BaseAttribute
}
The problem is simply that the AllowMultiple check only compares attributes of the same actual type (i.e. the concrete type instantiated) - and is perhaps best used with sealed attributes for this reason.
It will, for example, enforce the following (as an illegal duplicate), inheriting this from BaseAttribute:
[DerivedAttributeB()]
[DerivedAttributeB()]
public string Name { get; set; }
In short, I don't think you can do what you want here... (enforce no more than one instance including subclasses of BaseAttribute per property).
A similar example of this problem would be:
[Description("abc")]
[I18NDescriptionAttribute("abc")]
public string Name { get; set; }
class I18NDescriptionAttribute : DescriptionAttribute {
public I18NDescriptionAttribute(string resxKey) : base(resxKey) { }
}
The intent above is to provide a [Description] from resx at runtime (fully supported by ComponentModel etc) - but it can't stop you also adding a [Description].

Categories

Resources