Nick Bull
Nick Bull

Reputation: 9866

Generic abstract class inheritance

Explanation:

I have an abstract class like so:

public abstract class Serializer<T> where T : new()
{
    T obj { get; set; }

    public string ToXML()
    {
        // return string XML
    }
}

And another class that inherits this abstract class:

public class Account : Serializer<Account>
{
    // Code
    // I don't want to have to implement the methods of 
    // the inherited class/interface.

}

I want to access it like such:

Account account = new Account();
Console.WriteLine(account.ToXML());

Question:

Can I do this and pass the account to the property obj so the ToXML can perform its task of converting the object to a string?

Serializer s = new Serializer();
s.ToXML(account);

I'd prefer to have each object inherit the Serialize class and all its methods, and just be able to know that without editing anything but adding the inheritance of the class that I can now access these methods.

On another note, I feel like inheriting a class violates the is-a and can-do principles between choosing an interface or a class, but I don't want to override all the methods, when I already have the code written to do it generically in a class (i.e., I don't want to implement the interface). Is there a way to inherit the methods of an interface like a class (no implementing/overriding).

Upvotes: 2

Views: 670

Answers (4)

Donald Jansen
Donald Jansen

Reputation: 1985

If your code in the Abstract class will not change just to serialize the object, this approach doesn't make sense, Serialization you do not need to know the object type (Especially if your using xml which means building a easy to access string).

If you want the Serialization only available to certain objects make an interface i.e

public interface ISerialize
{
}

 public class Account : ISerialize
{
}

and then create an Extension method

public static class ExtenstionMethods
{
     public static string ToXml(this ISerialize obj)
     {
     // code to build xml string
     }
}

This way you can do what you want to do because Account is of the Interface and the ExtensionMethods will only work on that Interface, thus you only need the code in the ExtensionMethods class and then include the namespace wherever you want to use the "ToXml()" etc

Account account = new Account();
Console.WriteLine(account.ToXML());

Upvotes: 0

Jord&#227;o
Jord&#227;o

Reputation: 56467

Try to return this:

T obj { get { return (T)this; } }

But, this means that the child class has to provide itself as a type parameter, it's the curiously recurring "template" pattern... To be sure though, you don't necessarily need to know the type of the object at compile time to serialize it to XML (if you use the usual serializers), so accessing this within the serializer method would be OK, without the need for that type parameter and that property.

I'd personally prefer a more hands off approach to an abstract base class (using the XmlSerializer):

public interface MXmlSerializable { }
public static class XmlSerializable {
  public static string ToXml(this MXmlSerializable self) {
    if (self == null) throw new ArgumentNullException();
    var serializer = new XmlSerializer(self.GetType());
    using (var writer = new StringWriter()) {
      serializer.Serialize(writer, self);
      return writer.GetStringBuilder().ToString();
    }
  }
}

M stands for mixin. It's effectively a marker interface with an extension method. Use it like this:

public class Account : MXmlSerializable { 
  ... 
}

...

Account account = new Account();
...
string accountXml = account.ToXml();

Upvotes: 2

TGH
TGH

Reputation: 39248

What about just doing it like this;

public string ToXML()
    {
        convert `this` to xml directly  
        // return string XML
    }

Why do you need the property to return a reference to the class itself.

With the above structure you can do the following, without even needing the T property

Account account = new Account();
Console.WriteLine(account.ToXML());

Upvotes: 0

Ondrej Tucny
Ondrej Tucny

Reputation: 27962

Your construct hardly makes sense. There's no clear point for the Serializer<T> instance to point to itself. You can easily use this and cast it to T. Also, unless your ToXML method implements some really generic XML serialization algorithm (like processing the current instance via reflection), you should make it virtual and place the specific implementations in Serializer<T>'s ancestors.

Also, I would also object your approach to inheritance. If your Account class is in fact a single purpose account serializer, then name it so (AccountSerializer). If not, and Account represents an actual account, then yes, from an independent reader's point of view you are mixing two primary concepts: a business object (Account) and some technical mechanism (Serializer<T>).

If you have a general-purpose serialization algorith, why don't you just have a separate, non-abstract Serializer<T> class, accepting T instances in ToXML()? You will end up with better separation of concerns.

Is there a way to inherit the methods of an interface like a class (no implementing/overriding).

No. Interfaces are interfaces, not classes than embed particular code.

Upvotes: 0

Related Questions