nxn
nxn

Reputation: 119

Generic class with multiple return types

I know my question is not perfectly asked but it was rather hard so I will show with an example: So I have a class AbstractHandler. I create it with a method from another class:

class AbstractManager
{
    BinarySerializator binarySerializator; //just for the example    
    TextSerializator textSerializator;

    public AbstractManager(BinarySerializator binarySerializator) {
        this.binarySerializator = binarySerializator;
        this.textSerializator = null;
    }

    public AbstractManager(TextSerializator textSerializator) {
        this.textSerializator = textSerializator;
        this.binarySerializator = null;
    }

    public AbstractHandler createHandler() {
        if (this.binarySerializator != null) {
            return new AbstractHandler<byte[]>(this.binarySerializator);
        } else {
            return new AbstractHandler<String>(this.textSerializator);
        }
    }
}

So this is how I create the AbstractHandler which again has the two constructors (one that takes a BinarySerializator and another for TextSerializator). Now here is the fun part: both Serializators have a method which is getSerializedType(Object object), the binary returns byte[] the text returns String. I want my method in the AbstractHandler to return either byte[] or String depending on the type of serializator I have:

public T createSerializable(Object object) {
   if (binarySerializer != null) {
     return (T) binarySerializer.getSerializedType(object);
   }

   if (textSerializer != null) {
     return (T) textSerializer.getSerializedType(object);
   }
}

My question is - is this the way to do it? Also is there a workaround with the two constructors and how am I supposed to deal with the two different AbstractHandlers, I know it's possible to be done with generics instead of havign two classes (one for String, one for byte[]). Thanks for taking your time to read this long post.

Upvotes: 1

Views: 618

Answers (1)

romain-aga
romain-aga

Reputation: 1561

I have two solutions:

Interfaces:

interface ISerializatorStategy
{
    object GetSerializedType(object obj);
}

// If you want generic classes
interface ISerializatorStategy<T> : ISerializatorStategy
{
    new T GetSerializedType(object obj);
}

Serializators:

// If you don't want generic classes
// you can inherit from the base interface and implement only its method
class TextSerializator : ISerializatorStategy<string>
{
    public string GetSerializedType(object obj)
    {
        return "Hello World";
    }

    object ISerializatorStategy.GetSerializedType(object obj)
    {
        return GetSerializedType(obj);
    }
}

class IntSerializator : ISerializatorStategy<int>
{
    public int GetSerializedType(object obj)
    {
        return 42;
    }

    object ISerializatorStategy.GetSerializedType(object obj)
    {
        return GetSerializedType(obj);
    }
}

Managers:

class AbstractManager
{
    protected ISerializatorStategy SerializatorStrategy { get; set; }

    public AbstractManager(ISerializatorStategy serializatorStrategy)
    {
        SerializatorStrategy = serializatorStrategy;
    }

    public AbstractHandler CreateHandler()
    {
        return new AbstractHandler(SerializatorStrategy);
    }
}

// If you want generic classes
class AbstractManager<T> : AbstractManager
{
    // Note, if you allow this constructor,
    // you could encounter runtime errors
    public AbstractManager(ISerializatorStategy serializatorStrategy)
        : base(serializatorStrategy)
    {
    }

    public AbstractManager(ISerializatorStategy<T> serializatorStrategy)
        : base(serializatorStrategy)
    {
    }

    public new AbstractHandler<T> CreateHandler()
    {
        return new AbstractHandler<T>(SerializatorStrategy);
    }
}

Handlers:

class AbstractHandler
{
    private readonly ISerializatorStategy _serializatorStrategy;

    public AbstractHandler(ISerializatorStategy serializatorStrategy)
    {
        _serializatorStrategy = serializatorStrategy;
    }

    public object CreateSerializable(object obj)
    {
        return _serializatorStrategy.GetSerializedType(obj);
    }

    public void GetSerializable<T>(object obj, out T serializebleObject)
    {
        serializebleObject = (T)_serializatorStrategy.GetSerializedType(obj);
    }
}

// If you want generic classes
class AbstractHandler<T> : AbstractHandler
{
    // Note, if you allow this constructor,
    // you could encounter runtime errors
    public AbstractHandler(ISerializatorStategy serializatorStrategy)
        : base(serializatorStrategy)
    {
    }

    public AbstractHandler(ISerializatorStategy<T> serializatorStrategy)
        : base(serializatorStrategy)
    {
    }

    public new T CreateSerializable(object obj)
    {
        return (T)base.CreateSerializable(obj);
    }
}

Usage:

Generic Classes

class Program
{
    static void Main(string[] args)
    {
        var textManager = new AbstractManager<string>(new TextSerializator());
        var textHandler = textManager.CreateHandler();
        string textResult = textHandler.CreateSerializable(null); // or AbstractHandler<string> as type
        Console.WriteLine(textResult);

        var intManager = new AbstractManager<int>(new IntSerializator());
        var intHandler = intManager.CreateHandler(); // or AbstractHandler<int> as type
        int intResult = intHandler.CreateSerializable(null);
        Console.WriteLine(intResult);

        Console.ReadKey();
    }
}

Generic Methods

class Program
{
    static void Main(string[] args)
    {
        AbstractManager manager = new AbstractManager(new TextSerializator());
        AbstractHandler handler = manager.createHandler();
        string textResult;
        handler.GetSerializable(null, out textResult);
        Console.WriteLine(textResult);

        manager = new AbstractManager(new IntSerializator());
        handler = manager.createHandler();
        int intResult;
        handler.GetSerializable(null, out intResult);
        Console.WriteLine(intResult);

        Console.ReadKey();
    }
}

Now, you shouldn't have troubles to apply this on your issue.

Upvotes: 1

Related Questions